1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2
3 /*
4 * GThumb
5 *
6 * Copyright (C) 2001-2008 Free Software Foundation, Inc.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include <config.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <glib.h>
28 #include <glib/gi18n.h>
29 #include <glib/gprintf.h>
30 #include <gio/gio.h>
31 #include "glib-utils.h"
32
33 #define MAX_PATTERNS 128
34
35
36 /* gobject utils*/
37
38
39 gpointer
_g_object_ref(gpointer object)40 _g_object_ref (gpointer object)
41 {
42 if (object != NULL)
43 return g_object_ref (object);
44 else
45 return NULL;
46 }
47
48
49 void
_g_object_unref(gpointer object)50 _g_object_unref (gpointer object)
51 {
52 if (object != NULL)
53 g_object_unref (object);
54 }
55
56
57 void
_g_object_clear(gpointer object)58 _g_object_clear (gpointer object)
59 {
60 gpointer *object_p = (gpointer *) object;
61
62 if ((object_p != NULL) && (*object_p != NULL)) {
63 g_object_unref (*object_p);
64 *object_p = NULL;
65 }
66 }
67
68
69 GList *
_g_object_list_ref(GList * list)70 _g_object_list_ref (GList *list)
71 {
72 GList *new_list;
73
74 if (list == NULL)
75 return NULL;
76
77 new_list = g_list_copy (list);
78 g_list_foreach (new_list, (GFunc) g_object_ref, NULL);
79
80 return new_list;
81 }
82
83
84 void
_g_object_list_unref(GList * list)85 _g_object_list_unref (GList *list)
86 {
87 g_list_foreach (list, (GFunc) g_object_unref, NULL);
88 g_list_free (list);
89 }
90
91
92 GType
g_object_list_get_type(void)93 g_object_list_get_type (void)
94 {
95 static GType type = 0;
96
97 if (type == 0)
98 type = g_boxed_type_register_static ("GObjectList",
99 (GBoxedCopyFunc) _g_object_list_ref,
100 (GBoxedFreeFunc) _g_object_list_unref);
101
102 return type;
103 }
104
105
106 GEnumValue *
_g_enum_type_get_value(GType enum_type,int value)107 _g_enum_type_get_value (GType enum_type,
108 int value)
109 {
110 GEnumClass *class;
111 GEnumValue *enum_value;
112
113 class = G_ENUM_CLASS (g_type_class_ref (enum_type));
114 enum_value = g_enum_get_value (class, value);
115 g_type_class_unref (class);
116
117 return enum_value;
118 }
119
120
121 GEnumValue *
_g_enum_type_get_value_by_nick(GType enum_type,const char * nick)122 _g_enum_type_get_value_by_nick (GType enum_type,
123 const char *nick)
124 {
125 GEnumClass *class;
126 GEnumValue *enum_value;
127
128 class = G_ENUM_CLASS (g_type_class_ref (enum_type));
129 enum_value = g_enum_get_value_by_nick (class, nick);
130 g_type_class_unref (class);
131
132 return enum_value;
133 }
134
135
136 /* idle callback */
137
138
139 IdleCall*
idle_call_new(DataFunc func,gpointer data)140 idle_call_new (DataFunc func,
141 gpointer data)
142 {
143 IdleCall *call = g_new0 (IdleCall, 1);
144 call->func = func;
145 call->data = data;
146 return call;
147 }
148
149
150 void
idle_call_free(IdleCall * call)151 idle_call_free (IdleCall *call)
152 {
153 g_free (call);
154 }
155
156
157 static gboolean
idle_call_exec_cb(gpointer data)158 idle_call_exec_cb (gpointer data)
159 {
160 IdleCall *call = data;
161 (*call->func) (call->data);
162 return FALSE;
163 }
164
165
166 guint
idle_call_exec(IdleCall * call,gboolean use_idle_cb)167 idle_call_exec (IdleCall *call,
168 gboolean use_idle_cb)
169 {
170 if (use_idle_cb)
171 return g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
172 idle_call_exec_cb,
173 call,
174 (GDestroyNotify) idle_call_free);
175 else {
176 (*call->func) (call->data);
177 idle_call_free (call);
178 return 0;
179 }
180 }
181
182
183 guint
call_when_idle(DataFunc func,gpointer data)184 call_when_idle (DataFunc func,
185 gpointer data)
186 {
187 return idle_call_exec (idle_call_new (func, data), TRUE);
188 }
189
190
191 typedef struct {
192 gpointer object;
193 ReadyCallback ready_func;
194 gpointer user_data;
195 GError *error;
196 guint id;
197 } ObjectReadyData;
198
199
200 static gboolean
exec_object_ready_func(gpointer user_data)201 exec_object_ready_func (gpointer user_data)
202 {
203 ObjectReadyData *data = user_data;
204
205 g_source_remove (data->id);
206 data->ready_func (G_OBJECT (data->object), data->error, data->user_data);
207 g_free (data);
208
209 return FALSE;
210 }
211
212
213 void
object_ready_with_error(gpointer object,ReadyCallback ready_func,gpointer user_data,GError * error)214 object_ready_with_error (gpointer object,
215 ReadyCallback ready_func,
216 gpointer user_data,
217 GError *error)
218 {
219 ObjectReadyData *data;
220
221 data = g_new0 (ObjectReadyData, 1);
222
223 data->object = object;
224 data->ready_func = ready_func;
225 data->user_data = user_data;
226 data->error = error;
227 data->id = g_idle_add (exec_object_ready_func, data);
228 }
229
230
231 typedef struct {
232 ReadyFunc ready_func;
233 gpointer user_data;
234 GError *error;
235 guint id;
236 } ReadyData;
237
238
239 static gboolean
exec_ready_func(gpointer user_data)240 exec_ready_func (gpointer user_data)
241 {
242 ReadyData *data = user_data;
243
244 g_source_remove (data->id);
245 data->ready_func (data->error, data->user_data);
246 g_free (data);
247
248 return FALSE;
249 }
250
251
252 void
ready_with_error(ReadyFunc ready_func,gpointer user_data,GError * error)253 ready_with_error (ReadyFunc ready_func,
254 gpointer user_data,
255 GError *error)
256 {
257 ReadyData *data;
258
259 data = g_new0 (ReadyData, 1);
260 data->ready_func = ready_func;
261 data->user_data = user_data;
262 data->error = error;
263 data->id = g_idle_add (exec_ready_func, data);
264 }
265
266
267 /* debug */
268
269
270 void
debug(const char * file,int line,const char * function,const char * format,...)271 debug (const char *file,
272 int line,
273 const char *function,
274 const char *format,
275 ...)
276 {
277 #ifdef DEBUG
278 static gboolean first_time = 0;
279 static gboolean print_debug_info = 0;
280 va_list args;
281 char *str;
282
283 if (! first_time) {
284 first_time = 1;
285 if (g_getenv ("GOOBOX_DEBUG"))
286 print_debug_info = 1;
287 }
288
289 if (! print_debug_info)
290 return;
291
292 g_return_if_fail (format != NULL);
293
294 va_start (args, format);
295 str = g_strdup_vprintf (format, args);
296 va_end (args);
297
298 g_fprintf (stderr, "[%s] %s:%d (%s):\n\t%s\n", g_get_prgname(), file, line, function, str);
299
300 g_free (str);
301 #endif
302 }
303
304
305 void
performance(const char * file,int line,const char * function,const char * format,...)306 performance (const char *file,
307 int line,
308 const char *function,
309 const char *format,
310 ...)
311 {
312 #ifdef DEBUG
313 va_list args;
314 char *formatted, *str, *filename;
315
316 filename = g_path_get_basename (file);
317
318 va_start (args, format);
319 formatted = g_strdup_vprintf (format, args);
320 va_end (args);
321
322 str = g_strdup_printf ("MARK: %s: (%s:%d) [%s] : %s", g_get_prgname(), filename, line, function, formatted);
323 g_free (formatted);
324
325 access (str, F_OK);
326 g_free (str);
327 g_free (filename);
328 #endif
329 }
330
331
332 /* GTimeVal utils */
333
334
335 int
_g_time_val_cmp(GTimeVal * a,GTimeVal * b)336 _g_time_val_cmp (GTimeVal *a,
337 GTimeVal *b)
338 {
339 if (a->tv_sec == b->tv_sec) {
340 if (a->tv_usec == b->tv_usec)
341 return 0;
342 else
343 return a->tv_usec > b->tv_usec ? 1 : -1;
344 }
345 else if (a->tv_sec > b->tv_sec)
346 return 1;
347 else
348 return -1;
349 }
350
351
352 void
_g_time_val_reset(GTimeVal * time_)353 _g_time_val_reset (GTimeVal *time_)
354 {
355 time_->tv_sec = 0;
356 time_->tv_usec = 0;
357 }
358
359
360 gboolean
_g_time_val_from_exif_date(const char * exif_date,GTimeVal * time_)361 _g_time_val_from_exif_date (const char *exif_date,
362 GTimeVal *time_)
363 {
364 struct tm tm;
365 long val;
366
367 g_return_val_if_fail (time_ != NULL, FALSE);
368
369 if (exif_date == NULL)
370 return FALSE;
371
372 while (g_ascii_isspace (*exif_date))
373 exif_date++;
374
375 if (*exif_date == '\0')
376 return FALSE;
377
378 if (! g_ascii_isdigit (*exif_date))
379 return FALSE;
380
381 /* YYYY */
382
383 val = g_ascii_strtoull (exif_date, (char **)&exif_date, 10);
384 tm.tm_year = val - 1900;
385
386 if (*exif_date != ':')
387 return FALSE;
388
389 /* MM */
390
391 exif_date++;
392 tm.tm_mon = g_ascii_strtoull (exif_date, (char **)&exif_date, 10) - 1;
393
394 if (*exif_date != ':')
395 return FALSE;
396
397 /* DD */
398
399 exif_date++;
400 tm.tm_mday = g_ascii_strtoull (exif_date, (char **)&exif_date, 10);
401
402 if (*exif_date != ' ')
403 return FALSE;
404
405 /* hh */
406
407 val = g_ascii_strtoull (exif_date, (char **)&exif_date, 10);
408 tm.tm_hour = val;
409
410 if (*exif_date != ':')
411 return FALSE;
412
413 /* mm */
414
415 exif_date++;
416 tm.tm_min = g_ascii_strtoull (exif_date, (char **)&exif_date, 10);
417
418 if (*exif_date != ':')
419 return FALSE;
420
421 /* ss */
422
423 exif_date++;
424 tm.tm_sec = strtoul (exif_date, (char **)&exif_date, 10);
425
426 time_->tv_sec = mktime (&tm);
427 time_->tv_usec = 0;
428
429 /* usec */
430
431 if ((*exif_date == ',') || (*exif_date == '.')) {
432 glong mul = 100000;
433
434 while (g_ascii_isdigit (*++exif_date)) {
435 time_->tv_usec += (*exif_date - '0') * mul;
436 mul /= 10;
437 }
438 }
439
440 while (g_ascii_isspace (*exif_date))
441 exif_date++;
442
443 return *exif_date == '\0';
444 }
445
446
447 char *
_g_time_val_to_exif_date(GTimeVal * time_)448 _g_time_val_to_exif_date (GTimeVal *time_)
449 {
450 char *retval;
451 struct tm *tm;
452 time_t secs;
453
454 g_return_val_if_fail (time_->tv_usec >= 0 && time_->tv_usec < G_USEC_PER_SEC, NULL);
455
456 secs = time_->tv_sec;
457 tm = localtime (&secs);
458
459 retval = g_strdup_printf ("%4d:%02d:%02d %02d:%02d:%02d",
460 tm->tm_year + 1900,
461 tm->tm_mon + 1,
462 tm->tm_mday,
463 tm->tm_hour,
464 tm->tm_min,
465 tm->tm_sec);
466
467 return retval;
468 }
469
470
471 /* Bookmark file utils */
472
473
474 void
_g_bookmark_file_clear(GBookmarkFile * bookmark)475 _g_bookmark_file_clear (GBookmarkFile *bookmark)
476 {
477 char **uris;
478 int i;
479
480 uris = g_bookmark_file_get_uris (bookmark, NULL);
481 for (i = 0; uris[i] != NULL; i++)
482 g_bookmark_file_remove_item (bookmark, uris[i], NULL);
483 g_strfreev (uris);
484 }
485
486
487 void
_g_bookmark_file_add_uri(GBookmarkFile * bookmark,const char * uri)488 _g_bookmark_file_add_uri (GBookmarkFile *bookmark,
489 const char *uri)
490 {
491 g_bookmark_file_set_is_private (bookmark, uri, TRUE);
492 g_bookmark_file_add_application (bookmark, uri, NULL, NULL);
493 }
494
495
496 void
_g_bookmark_file_set_uris(GBookmarkFile * bookmark,GList * uri_list)497 _g_bookmark_file_set_uris (GBookmarkFile *bookmark,
498 GList *uri_list)
499 {
500 GList *scan;
501
502 _g_bookmark_file_clear (bookmark);
503 for (scan = uri_list; scan; scan = scan->next)
504 _g_bookmark_file_add_uri (bookmark, scan->data);
505 }
506
507
508 /* String utils */
509
510
511 void
_g_strset(char ** s,const char * value)512 _g_strset (char **s,
513 const char *value)
514 {
515 if (*s == value)
516 return;
517
518 if (*s != NULL) {
519 g_free (*s);
520 *s = NULL;
521 }
522
523 if (value != NULL)
524 *s = g_strdup (value);
525 }
526
527
528 char *
_g_strdup_with_max_size(const char * s,int max_size)529 _g_strdup_with_max_size (const char *s,
530 int max_size)
531 {
532 char *result;
533 int l = strlen (s);
534
535 if (l > max_size) {
536 char *first_half;
537 char *second_half;
538 int offset;
539 int half_max_size = max_size / 2 + 1;
540
541 first_half = g_strndup (s, half_max_size);
542 offset = half_max_size + l - max_size;
543 second_half = g_strndup (s + offset, half_max_size);
544
545 result = g_strconcat (first_half, "...", second_half, NULL);
546
547 g_free (first_half);
548 g_free (second_half);
549 } else
550 result = g_strdup (s);
551
552 return result;
553 }
554
555
556 /**
557 * example 1 : "xxx##yy#" --> [0] = xxx
558 * [1] = ##
559 * [2] = yy
560 * [3] = #
561 * [4] = NULL
562 *
563 * example 2 : "" --> [0] = NULL
564 **/
565 char **
_g_get_template_from_text(const char * utf8_template)566 _g_get_template_from_text (const char *utf8_template)
567 {
568 const char *chunk_start = utf8_template;
569 char **str_vect;
570 GList *str_list = NULL, *scan;
571 int n = 0;
572
573 if (utf8_template == NULL)
574 return NULL;
575
576 while (*chunk_start != 0) {
577 gunichar ch;
578 gboolean reading_sharps;
579 char *chunk;
580 const char *chunk_end;
581 int chunk_len = 0;
582
583 reading_sharps = (g_utf8_get_char (chunk_start) == '#');
584 chunk_end = chunk_start;
585
586 ch = g_utf8_get_char (chunk_end);
587 while (reading_sharps
588 && (*chunk_end != 0)
589 && (ch == '#')) {
590 chunk_end = g_utf8_next_char (chunk_end);
591 ch = g_utf8_get_char (chunk_end);
592 chunk_len++;
593 }
594
595 ch = g_utf8_get_char (chunk_end);
596 while (! reading_sharps
597 && (*chunk_end != 0)
598 && (*chunk_end != '#')) {
599 chunk_end = g_utf8_next_char (chunk_end);
600 ch = g_utf8_get_char (chunk_end);
601 chunk_len++;
602 }
603
604 chunk = _g_utf8_strndup (chunk_start, chunk_len);
605 str_list = g_list_prepend (str_list, chunk);
606 n++;
607
608 chunk_start = chunk_end;
609 }
610
611 str_vect = g_new (char*, n + 1);
612
613 str_vect[n--] = NULL;
614 for (scan = str_list; scan; scan = scan->next)
615 str_vect[n--] = scan->data;
616
617 g_list_free (str_list);
618
619 return str_vect;
620 }
621
622
623 char *
_g_get_name_from_template(char ** utf8_template,int n)624 _g_get_name_from_template (char **utf8_template,
625 int n)
626 {
627 GString *s;
628 int i;
629 char *result;
630
631 s = g_string_new (NULL);
632
633 for (i = 0; utf8_template[i] != NULL; i++) {
634 const char *chunk = utf8_template[i];
635 gunichar ch = g_utf8_get_char (chunk);
636
637 if (ch != '#')
638 g_string_append (s, chunk);
639 else {
640 char *s_n;
641 int s_n_len;
642 int sharps_len = g_utf8_strlen (chunk, -1);
643
644 s_n = g_strdup_printf ("%d", n);
645 s_n_len = strlen (s_n);
646
647 while (s_n_len < sharps_len) {
648 g_string_append_c (s, '0');
649 sharps_len--;
650 }
651
652 g_string_append (s, s_n);
653 g_free (s_n);
654 }
655 }
656
657 result = s->str;
658 g_string_free (s, FALSE);
659
660 return result;
661 }
662
663
664 char *
_g_replace(const char * str,const char * from_str,const char * to_str)665 _g_replace (const char *str,
666 const char *from_str,
667 const char *to_str)
668 {
669 char **tokens;
670 int i;
671 GString *gstr;
672
673 if (str == NULL)
674 return NULL;
675
676 if (from_str == NULL)
677 return g_strdup (str);
678
679 if (strcmp (str, from_str) == 0)
680 return g_strdup (to_str);
681
682 tokens = g_strsplit (str, from_str, -1);
683
684 gstr = g_string_new (NULL);
685 for (i = 0; tokens[i] != NULL; i++) {
686 g_string_append (gstr, tokens[i]);
687 if ((to_str != NULL) && (tokens[i+1] != NULL))
688 g_string_append (gstr, to_str);
689 }
690
691 g_strfreev (tokens);
692
693 return g_string_free (gstr, FALSE);
694 }
695
696
697 char *
_g_replace_pattern(const char * utf8_text,gunichar pattern,const char * value)698 _g_replace_pattern (const char *utf8_text,
699 gunichar pattern,
700 const char *value)
701 {
702 const char *s;
703 GString *r;
704 char *r_str;
705
706 if (utf8_text == NULL)
707 return NULL;
708
709 if (g_utf8_strchr (utf8_text, -1, '%') == NULL)
710 return g_strdup (utf8_text);
711
712 r = g_string_new (NULL);
713 for (s = utf8_text; *s != 0; s = g_utf8_next_char (s)) {
714 gunichar ch = g_utf8_get_char (s);
715
716 if (ch == '%') {
717 s = g_utf8_next_char (s);
718
719 if (*s == 0) {
720 g_string_append_unichar (r, ch);
721 break;
722 }
723
724 ch = g_utf8_get_char (s);
725 if (ch == pattern) {
726 if (value)
727 g_string_append (r, value);
728 }
729 else {
730 g_string_append (r, "%");
731 g_string_append_unichar (r, ch);
732 }
733
734 } else
735 g_string_append_unichar (r, ch);
736 }
737
738 r_str = r->str;
739 g_string_free (r, FALSE);
740
741 return r_str;
742 }
743
744
745 char *
_g_utf8_replace(const char * string,const char * pattern,const char * replacement)746 _g_utf8_replace (const char *string,
747 const char *pattern,
748 const char *replacement)
749 {
750 GRegex *regex;
751 char *result;
752
753 if (string == NULL)
754 return NULL;
755
756 regex = g_regex_new (pattern, 0, 0, NULL);
757 if (regex == NULL)
758 return NULL;
759
760 result = g_regex_replace_literal (regex, string, -1, 0, replacement, 0, NULL);
761
762 g_regex_unref (regex);
763
764 return result;
765 }
766
767
768 char *
_g_utf8_strndup(const char * str,gsize n)769 _g_utf8_strndup (const char *str,
770 gsize n)
771 {
772 const char *s = str;
773 char *result;
774
775 while (n && *s) {
776 s = g_utf8_next_char (s);
777 n--;
778 }
779
780 result = g_strndup (str, s - str);
781
782 return result;
783 }
784
785
786 static const char *
_g_utf8_strstr(const char * haystack,const char * needle)787 _g_utf8_strstr (const char *haystack,
788 const char *needle)
789 {
790 const char *s;
791 gsize i;
792 gsize haystack_len = g_utf8_strlen (haystack, -1);
793 gsize needle_len = g_utf8_strlen (needle, -1);
794 int needle_size = strlen (needle);
795
796 s = haystack;
797 for (i = 0; i <= haystack_len - needle_len; i++) {
798 if (strncmp (s, needle, needle_size) == 0)
799 return s;
800 s = g_utf8_next_char(s);
801 }
802
803 return NULL;
804 }
805
806
807 char **
_g_utf8_strsplit(const char * string,const char * delimiter,int max_tokens)808 _g_utf8_strsplit (const char *string,
809 const char *delimiter,
810 int max_tokens)
811 {
812 GSList *string_list = NULL, *slist;
813 char **str_array;
814 const char *s;
815 guint n = 0;
816 const char *remainder;
817
818 g_return_val_if_fail (string != NULL, NULL);
819 g_return_val_if_fail (delimiter != NULL, NULL);
820 g_return_val_if_fail (delimiter[0] != '\0', NULL);
821
822 if (max_tokens < 1)
823 max_tokens = G_MAXINT;
824
825 remainder = string;
826 s = _g_utf8_strstr (remainder, delimiter);
827 if (s != NULL) {
828 gsize delimiter_size = strlen (delimiter);
829
830 while (--max_tokens && (s != NULL)) {
831 gsize size = s - remainder;
832 char *new_string;
833
834 new_string = g_new (char, size + 1);
835 strncpy (new_string, remainder, size);
836 new_string[size] = 0;
837
838 string_list = g_slist_prepend (string_list, new_string);
839 n++;
840 remainder = s + delimiter_size;
841 s = _g_utf8_strstr (remainder, delimiter);
842 }
843 }
844 if (*string) {
845 n++;
846 string_list = g_slist_prepend (string_list, g_strdup (remainder));
847 }
848
849 str_array = g_new (char*, n + 1);
850
851 str_array[n--] = NULL;
852 for (slist = string_list; slist; slist = slist->next)
853 str_array[n--] = slist->data;
854
855 g_slist_free (string_list);
856
857 return str_array;
858 }
859
860
861 char *
_g_utf8_strstrip(const char * str)862 _g_utf8_strstrip (const char *str)
863 {
864 if (str == NULL)
865 return NULL;
866 return g_strstrip (g_strdup (str));
867 }
868
869
870 gboolean
_g_utf8_all_spaces(const char * utf8_string)871 _g_utf8_all_spaces (const char *utf8_string)
872 {
873 gunichar c;
874
875 if (utf8_string == NULL)
876 return TRUE;
877
878 c = g_utf8_get_char (utf8_string);
879 while (c != 0) {
880 if (! g_unichar_isspace (c))
881 return FALSE;
882 utf8_string = g_utf8_next_char (utf8_string);
883 c = g_utf8_get_char (utf8_string);
884 }
885
886 return TRUE;
887 }
888
889
890 char *
_g_utf8_remove_extension(const char * str)891 _g_utf8_remove_extension (const char *str)
892 {
893 char *p;
894 char *ext;
895 char *dest;
896
897 if ((str == NULL) || ! g_utf8_validate (str, -1, NULL))
898 return NULL;
899
900 p = (char *) str;
901 ext = g_utf8_strrchr (p, -1, g_utf8_get_char ("."));
902 dest = g_strdup (p);
903 g_utf8_strncpy (dest, p, g_utf8_strlen (p, -1) - g_utf8_strlen (ext, -1));
904
905 return dest;
906 }
907
908
909 GList *
_g_list_insert_list_before(GList * list1,GList * sibling,GList * list2)910 _g_list_insert_list_before (GList *list1,
911 GList *sibling,
912 GList *list2)
913 {
914 if (!list2)
915 {
916 return list1;
917 }
918 else if (!list1)
919 {
920 return list2;
921 }
922 else if (sibling)
923 {
924 GList *list2_last = g_list_last (list2);
925 if (sibling->prev)
926 {
927 sibling->prev->next = list2;
928 list2->prev = sibling->prev;
929 sibling->prev = list2_last;
930 list2_last->next = sibling;
931 return list1;
932 }
933 else
934 {
935 sibling->prev = list2_last;
936 list2_last->next = sibling;
937 return list2;
938 }
939 }
940 else
941 {
942 return g_list_concat (list1, list2);
943 }
944 }
945
946
947 GHashTable *static_strings = NULL;
948
949
950 const char *
get_static_string(const char * s)951 get_static_string (const char *s)
952 {
953 static GMutex static_strings_mutex;
954 const char *result;
955
956 if (s == NULL)
957 return NULL;
958
959 g_mutex_lock (&static_strings_mutex);
960
961 if (static_strings == NULL)
962 static_strings = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
963
964 if (! g_hash_table_lookup_extended (static_strings, s, (gpointer) &result, NULL)) {
965 result = g_strdup (s);
966 g_hash_table_insert (static_strings,
967 (gpointer) result,
968 GINT_TO_POINTER (1));
969 }
970
971 g_mutex_unlock (&static_strings_mutex);
972
973 return result;
974 }
975
976
977 char *
_g_rand_string(int len)978 _g_rand_string (int len)
979 {
980 static char *alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
981 static int letters_only = 52;
982 static int whole_alphabet = 62;
983 char *s;
984 GRand *rand_gen;
985 int i;
986
987 s = g_malloc (sizeof (char) * (len + 1));
988 rand_gen = g_rand_new ();
989 for (i = 0; i < len; i++)
990 s[i] = alphabet[g_rand_int_range (rand_gen, 0, (i == 0) ? letters_only : whole_alphabet)];
991 g_rand_free (rand_gen);
992 s[len] = 0;
993
994 return s;
995 }
996
997
998 int
_g_strv_find(char ** v,const char * s)999 _g_strv_find (char **v,
1000 const char *s)
1001 {
1002 int i;
1003
1004 for (i = 0; v[i] != NULL; i++) {
1005 if (strcmp (v[i], s) == 0)
1006 return i;
1007 }
1008
1009 return -1;
1010 }
1011
1012
1013 char *
_g_str_remove_suffix(const char * s,const char * suffix)1014 _g_str_remove_suffix (const char *s,
1015 const char *suffix)
1016 {
1017 int s_len;
1018 int suffix_len;
1019
1020 if (s == NULL)
1021 return NULL;
1022 if (suffix == NULL)
1023 return g_strdup (s);
1024
1025 s_len = strlen (s);
1026 suffix_len = strlen (suffix);
1027
1028 if (suffix_len >= s_len)
1029 return g_strdup ("");
1030 else
1031 return g_strndup (s, s_len - suffix_len);
1032 }
1033
1034
1035 /* Regexp utils */
1036
1037 static char **
get_patterns_from_pattern(const char * pattern_string)1038 get_patterns_from_pattern (const char *pattern_string)
1039 {
1040 char **patterns;
1041 int i;
1042
1043 if (pattern_string == NULL)
1044 return NULL;
1045
1046 patterns = _g_utf8_strsplit (pattern_string, ";", MAX_PATTERNS);
1047 for (i = 0; patterns[i] != NULL; i++) {
1048 char *p1, *p2;
1049
1050 p1 = _g_utf8_strstrip (patterns[i]);
1051 p2 = _g_replace (p1, ".", "\\.");
1052 patterns[i] = _g_replace (p2, "*", ".*");
1053
1054 g_free (p2);
1055 g_free (p1);
1056 }
1057
1058 return patterns;
1059 }
1060
1061
1062 GRegex **
get_regexps_from_pattern(const char * pattern_string,GRegexCompileFlags compile_options)1063 get_regexps_from_pattern (const char *pattern_string,
1064 GRegexCompileFlags compile_options)
1065 {
1066 char **patterns;
1067 GRegex **regexps;
1068 int i;
1069
1070 patterns = get_patterns_from_pattern (pattern_string);
1071 if (patterns == NULL)
1072 return NULL;
1073
1074 regexps = g_new0 (GRegex*, g_strv_length (patterns) + 1);
1075 for (i = 0; patterns[i] != NULL; i++)
1076 regexps[i] = g_regex_new (patterns[i],
1077 G_REGEX_OPTIMIZE | compile_options,
1078 G_REGEX_MATCH_NOTEMPTY,
1079 NULL);
1080 g_strfreev (patterns);
1081
1082 return regexps;
1083 }
1084
1085
1086 gboolean
string_matches_regexps(GRegex ** regexps,const char * string,GRegexMatchFlags match_options)1087 string_matches_regexps (GRegex **regexps,
1088 const char *string,
1089 GRegexMatchFlags match_options)
1090 {
1091 gboolean matched;
1092 int i;
1093
1094 if ((regexps == NULL) || (regexps[0] == NULL))
1095 return TRUE;
1096
1097 if (string == NULL)
1098 return FALSE;
1099
1100 matched = FALSE;
1101 for (i = 0; regexps[i] != NULL; i++)
1102 if (g_regex_match (regexps[i], string, match_options, NULL)) {
1103 matched = TRUE;
1104 break;
1105 }
1106
1107 return matched;
1108 }
1109
1110
1111 void
free_regexps(GRegex ** regexps)1112 free_regexps (GRegex **regexps)
1113 {
1114 int i;
1115
1116 if (regexps == NULL)
1117 return;
1118
1119 for (i = 0; regexps[i] != NULL; i++)
1120 g_regex_unref (regexps[i]);
1121 g_free (regexps);
1122 }
1123
1124
1125 /* URI utils */
1126
1127
1128 const char *
get_home_uri(void)1129 get_home_uri (void)
1130 {
1131 static char *home_uri = NULL;
1132
1133 if (home_uri == NULL) {
1134 const char *path;
1135 char *uri;
1136
1137 path = g_get_home_dir ();
1138 uri = g_uri_escape_string (path, G_URI_RESERVED_CHARS_ALLOWED_IN_PATH, TRUE);
1139
1140 home_uri = g_strconcat ("file://", uri, NULL);
1141
1142 g_free (uri);
1143 }
1144
1145 return home_uri;
1146 }
1147
1148
1149 const char *
get_desktop_uri(void)1150 get_desktop_uri (void)
1151 {
1152 static char *desktop_uri = NULL;
1153
1154 if (desktop_uri == NULL) {
1155 const char *path;
1156
1157 path = g_get_user_special_dir (G_USER_DIRECTORY_DESKTOP);
1158 desktop_uri = g_filename_to_uri (path, NULL, NULL);
1159 }
1160
1161 return desktop_uri;
1162 }
1163
1164
1165 int
uricmp(const char * uri1,const char * uri2)1166 uricmp (const char *uri1,
1167 const char *uri2)
1168 {
1169 if (uri1 == NULL) {
1170 if (uri2 == NULL)
1171 return 0;
1172 else
1173 return -1;
1174 }
1175
1176 if (uri2 == NULL) {
1177 if (uri1 == NULL)
1178 return 0;
1179 else
1180 return 1;
1181 }
1182
1183 return g_strcmp0 (uri1, uri2);
1184 }
1185
1186
1187 gboolean
same_uri(const char * uri1,const char * uri2)1188 same_uri (const char *uri1,
1189 const char *uri2)
1190 {
1191 return uricmp (uri1, uri2) == 0;
1192 }
1193
1194
1195 void
_g_string_list_free(GList * string_list)1196 _g_string_list_free (GList *string_list)
1197 {
1198 if (string_list == NULL)
1199 return;
1200 g_list_foreach (string_list, (GFunc) g_free, NULL);
1201 g_list_free (string_list);
1202
1203 }
1204
1205
1206 GList *
_g_string_list_dup(GList * string_list)1207 _g_string_list_dup (GList *string_list)
1208 {
1209 GList *new_list = NULL;
1210 GList *scan;
1211
1212 for (scan = string_list; scan; scan = scan->next)
1213 new_list = g_list_prepend (new_list, g_strdup (scan->data));
1214
1215 return g_list_reverse (new_list);
1216 }
1217
1218
1219 GType
g_string_list_get_type(void)1220 g_string_list_get_type (void)
1221 {
1222 static GType type = 0;
1223
1224 if (type == 0)
1225 type = g_boxed_type_register_static ("GStringList",
1226 (GBoxedCopyFunc) _g_string_list_dup,
1227 (GBoxedFreeFunc) _g_string_list_free);
1228
1229 return type;
1230 }
1231
1232
1233 GList *
get_file_list_from_url_list(char * url_list)1234 get_file_list_from_url_list (char *url_list)
1235 {
1236 GList *list = NULL;
1237 int i;
1238 char *url_start, *url_end;
1239
1240 url_start = url_list;
1241 while (url_start[0] != '\0') {
1242 char *url;
1243
1244 if (strncmp (url_start, "file:", 5) == 0) {
1245 url_start += 5;
1246 if ((url_start[0] == '/')
1247 && (url_start[1] == '/')) url_start += 2;
1248 }
1249
1250 i = 0;
1251 while ((url_start[i] != '\0')
1252 && (url_start[i] != '\r')
1253 && (url_start[i] != '\n')) i++;
1254 url_end = url_start + i;
1255
1256 url = g_strndup (url_start, url_end - url_start);
1257 list = g_list_prepend (list, url);
1258
1259 url_start = url_end;
1260 i = 0;
1261 while ((url_start[i] != '\0')
1262 && ((url_start[i] == '\r')
1263 || (url_start[i] == '\n'))) i++;
1264 url_start += i;
1265 }
1266
1267 return g_list_reverse (list);
1268 }
1269
1270
1271 const char *
_g_uri_get_basename(const char * uri)1272 _g_uri_get_basename (const char *uri)
1273 {
1274 register char *base;
1275 register gssize last_char;
1276
1277 if (uri == NULL)
1278 return NULL;
1279
1280 if (uri[0] == '\0')
1281 return "";
1282
1283 last_char = strlen (uri) - 1;
1284
1285 if (uri[last_char] == G_DIR_SEPARATOR)
1286 return "";
1287
1288 base = g_utf8_strrchr (uri, -1, G_DIR_SEPARATOR);
1289 if (! base)
1290 return uri;
1291
1292 return base + 1;
1293 }
1294
1295
1296 const char *
_g_uri_get_file_extension(const char * uri)1297 _g_uri_get_file_extension (const char *uri)
1298 {
1299 int len;
1300 int p;
1301 const char *ptr = uri;
1302
1303 if (uri == NULL)
1304 return NULL;
1305
1306 len = strlen (uri);
1307 if (len <= 1)
1308 return NULL;
1309
1310 p = len - 1;
1311 while ((p >= 0) && (ptr[p] != '.'))
1312 p--;
1313
1314 if (p < 0)
1315 return NULL;
1316
1317 return uri + p;
1318 }
1319
1320
1321 static gboolean
uri_is_filetype(const char * uri,GFileType file_type)1322 uri_is_filetype (const char *uri,
1323 GFileType file_type)
1324 {
1325 gboolean result = FALSE;
1326 GFile *file;
1327 GFileInfo *info;
1328 GError *error = NULL;
1329
1330 file = g_file_new_for_uri (uri);
1331
1332 if (! g_file_query_exists (file, NULL)) {
1333 g_object_unref (file);
1334 return FALSE;
1335 }
1336
1337 info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_TYPE, 0, NULL, &error);
1338 if (error == NULL) {
1339 result = (g_file_info_get_file_type (info) == file_type);
1340 }
1341 else {
1342 g_warning ("Failed to get file type for uri %s: %s", uri, error->message);
1343 g_error_free (error);
1344 }
1345
1346 g_object_unref (info);
1347 g_object_unref (file);
1348
1349 return result;
1350 }
1351
1352
1353 gboolean
_g_uri_is_file(const char * uri)1354 _g_uri_is_file (const char *uri)
1355 {
1356 return uri_is_filetype (uri, G_FILE_TYPE_REGULAR);
1357 }
1358
1359
1360 gboolean
_g_uri_is_dir(const char * uri)1361 _g_uri_is_dir (const char *uri)
1362 {
1363 return uri_is_filetype (uri, G_FILE_TYPE_DIRECTORY);
1364 }
1365
1366
1367 gboolean
_g_uri_parent_of_uri(const char * dirname,const char * filename)1368 _g_uri_parent_of_uri (const char *dirname,
1369 const char *filename)
1370 {
1371 int dirname_l, filename_l, separator_position;
1372
1373 if ((dirname == NULL) || (filename == NULL))
1374 return FALSE;
1375
1376 dirname_l = strlen (dirname);
1377 filename_l = strlen (filename);
1378
1379 if ((dirname_l == filename_l + 1)
1380 && (dirname[dirname_l - 1] == '/'))
1381 return FALSE;
1382
1383 if ((filename_l == dirname_l + 1)
1384 && (filename[filename_l - 1] == '/'))
1385 return FALSE;
1386
1387 if (dirname[dirname_l - 1] == '/')
1388 separator_position = dirname_l - 1;
1389 else
1390 separator_position = dirname_l;
1391
1392 return ((filename_l > dirname_l)
1393 && (strncmp (dirname, filename, dirname_l) == 0)
1394 && (filename[separator_position] == '/'));
1395 }
1396
1397
1398 char *
_g_uri_get_parent(const char * uri)1399 _g_uri_get_parent (const char *uri)
1400 {
1401 int p;
1402 const char *ptr = uri;
1403 char *new_uri;
1404
1405 if (uri == NULL)
1406 return NULL;
1407
1408 p = strlen (uri) - 1;
1409 if (p < 0)
1410 return NULL;
1411
1412 while ((p > 0) && (ptr[p] != '/'))
1413 p--;
1414 if ((p == 0) && (ptr[p] == '/'))
1415 p++;
1416 new_uri = g_strndup (uri, (guint)p);
1417
1418 return new_uri;
1419 }
1420
1421
1422 char *
_g_uri_remove_extension(const char * uri)1423 _g_uri_remove_extension (const char *uri)
1424 {
1425 int len;
1426 int p;
1427 char *new_path;
1428
1429 if (uri == NULL)
1430 return NULL;
1431
1432 len = strlen (uri);
1433 if (len == 1)
1434 return g_strdup (uri);
1435
1436 p = len - 1;
1437 while ((p > 0) && (uri[p] != '.'))
1438 p--;
1439 if (p == 0)
1440 p = len;
1441 new_path = g_strndup (uri, (guint) p);
1442
1443 return new_path;
1444 }
1445
1446
1447 char *
_g_build_uri(const char * base,...)1448 _g_build_uri (const char *base, ...)
1449 {
1450 va_list args;
1451 const char *child;
1452 GString *uri;
1453
1454 uri = g_string_new (base);
1455
1456 va_start (args, base);
1457 while ((child = va_arg (args, const char *)) != NULL) {
1458 if (! g_str_has_suffix (uri->str, "/") && ! g_str_has_prefix (child, "/"))
1459 g_string_append (uri, "/");
1460 g_string_append (uri, child);
1461 }
1462 va_end (args);
1463
1464 return g_string_free (uri, FALSE);
1465 }
1466
1467
1468 /* GIO utils */
1469
1470
1471 gboolean
_g_file_equal(GFile * file1,GFile * file2)1472 _g_file_equal (GFile *file1,
1473 GFile *file2)
1474 {
1475 if ((file1 == NULL) && (file2 == NULL))
1476 return TRUE;
1477 if ((file1 == NULL) || (file2 == NULL))
1478 return FALSE;
1479
1480 return g_file_equal (file1, file2);
1481 }
1482
1483
1484 char *
_g_file_get_display_name(GFile * file)1485 _g_file_get_display_name (GFile *file)
1486 {
1487 char *name = NULL;
1488 GFileInfo *file_info;
1489
1490 file_info = g_file_query_info (file,
1491 G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME,
1492 G_FILE_QUERY_INFO_NONE,
1493 NULL,
1494 NULL);
1495 if (file_info != NULL)
1496 name = g_strdup (g_file_info_get_attribute_string (file_info, G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME));
1497 else
1498 name = g_file_get_parse_name (file);
1499
1500 return name;
1501 }
1502
1503
1504 GFileType
_g_file_get_standard_type(GFile * file)1505 _g_file_get_standard_type (GFile *file)
1506 {
1507 GFileType result;
1508 GFileInfo *info;
1509 GError *error = NULL;
1510
1511 info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_TYPE, 0, NULL, &error);
1512 if (error == NULL) {
1513 result = g_file_info_get_file_type (info);
1514 }
1515 else {
1516 result = G_FILE_ATTRIBUTE_TYPE_INVALID;
1517 g_error_free (error);
1518 }
1519
1520 g_object_unref (info);
1521
1522 return result;
1523 }
1524
1525
1526 GFile *
_g_file_get_destination(GFile * source,GFile * source_base,GFile * destination_folder)1527 _g_file_get_destination (GFile *source,
1528 GFile *source_base,
1529 GFile *destination_folder)
1530 {
1531 char *source_uri;
1532 const char *source_suffix;
1533 char *destination_folder_uri;
1534 char *destination_uri;
1535 GFile *destination;
1536
1537 source_uri = g_file_get_uri (source);
1538 if (source_base != NULL) {
1539 char *source_base_uri;
1540
1541 source_base_uri = g_file_get_uri (source_base);
1542 source_suffix = source_uri + strlen (source_base_uri);
1543
1544 g_free (source_base_uri);
1545 }
1546 else
1547 source_suffix = _g_uri_get_basename (source_uri);
1548
1549 destination_folder_uri = g_file_get_uri (destination_folder);
1550 destination_uri = g_strconcat (destination_folder_uri, "/", source_suffix, NULL);
1551 destination = g_file_new_for_uri (destination_uri);
1552
1553 g_free (destination_uri);
1554 g_free (destination_folder_uri);
1555 g_free (source_uri);
1556
1557 return destination;
1558 }
1559
1560
1561 GFile *
_g_file_get_child(GFile * file,...)1562 _g_file_get_child (GFile *file,
1563 ...)
1564 {
1565 va_list args;
1566 const char *name;
1567 GFile *child;
1568
1569 child = g_object_ref (file);
1570
1571 va_start (args, file);
1572 while ((name = va_arg (args, const char *)) != NULL) {
1573 GFile *tmp;
1574
1575 tmp = g_file_get_child (child, name);
1576 g_object_unref (child);
1577 child = tmp;
1578 }
1579 va_end (args);
1580
1581 return child;
1582 }
1583
1584
1585 GIcon *
_g_file_get_icon(GFile * file)1586 _g_file_get_icon (GFile *file)
1587 {
1588 GIcon *icon = NULL;
1589 GFileInfo *file_info;
1590
1591 file_info = g_file_query_info (file,
1592 G_FILE_ATTRIBUTE_STANDARD_ICON,
1593 G_FILE_QUERY_INFO_NONE,
1594 NULL,
1595 NULL);
1596 if (file_info != NULL)
1597 icon = (GIcon*) g_file_info_get_attribute_object (file_info, G_FILE_ATTRIBUTE_STANDARD_ICON);
1598 else
1599 icon = g_themed_icon_new ("file");
1600
1601 return icon;
1602 }
1603
1604
1605 GList *
_g_file_list_dup(GList * l)1606 _g_file_list_dup (GList *l)
1607 {
1608 GList *r = NULL, *scan;
1609 for (scan = l; scan; scan = scan->next)
1610 r = g_list_prepend (r, g_file_dup ((GFile*) scan->data));
1611 return g_list_reverse (r);
1612 }
1613
1614
1615 void
_g_file_list_free(GList * l)1616 _g_file_list_free (GList *l)
1617 {
1618 GList *scan;
1619 for (scan = l; scan; scan = scan->next)
1620 g_object_unref (scan->data);
1621 g_list_free (l);
1622 }
1623
1624
1625 GList *
_g_file_list_new_from_uri_list(GList * uris)1626 _g_file_list_new_from_uri_list (GList *uris)
1627 {
1628 GList *r = NULL, *scan;
1629 for (scan = uris; scan; scan = scan->next)
1630 r = g_list_prepend (r, g_file_new_for_uri ((char*)scan->data));
1631 return g_list_reverse (r);
1632 }
1633
1634
1635 GList *
_g_file_list_new_from_uriv(char ** uris)1636 _g_file_list_new_from_uriv (char **uris)
1637 {
1638 GList *r = NULL;
1639 int i;
1640
1641 if (uris == NULL)
1642 return NULL;
1643
1644 for (i = 0; uris[i] != NULL; i++)
1645 r = g_list_prepend (r, g_file_new_for_uri (uris[i]));
1646
1647 return g_list_reverse (r);
1648 }
1649
1650
1651 GList *
_g_file_list_find_file(GList * l,GFile * file)1652 _g_file_list_find_file (GList *l,
1653 GFile *file)
1654 {
1655 GList *scan;
1656
1657 for (scan = l; scan; scan = scan->next)
1658 if (g_file_equal (file, (GFile *) scan->data))
1659 return scan;
1660 return NULL;
1661 }
1662
1663
1664 const char*
_g_file_get_mime_type(GFile * file,gboolean fast_file_type)1665 _g_file_get_mime_type (GFile *file,
1666 gboolean fast_file_type)
1667 {
1668 GFileInfo *info;
1669 GError *err = NULL;
1670 const char *result = NULL;
1671
1672 info = g_file_query_info (file,
1673 fast_file_type ?
1674 G_FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE :
1675 G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
1676 0, NULL, &err);
1677 if (info == NULL) {
1678 char *uri;
1679
1680 uri = g_file_get_uri (file);
1681 g_warning ("could not get content type for %s: %s", uri, err->message);
1682 g_free (uri);
1683 g_clear_error (&err);
1684 }
1685 else {
1686 result = get_static_string (g_content_type_get_mime_type (g_file_info_get_content_type (info)));
1687 g_object_unref (info);
1688 }
1689
1690 return result;
1691 }
1692
1693
1694 void
_g_file_get_modification_time(GFile * file,GTimeVal * result)1695 _g_file_get_modification_time (GFile *file,
1696 GTimeVal *result)
1697 {
1698 GFileInfo *info;
1699 GError *err = NULL;
1700
1701 result->tv_sec = 0;
1702 result->tv_usec = 0;
1703
1704 info = g_file_query_info (file,
1705 G_FILE_ATTRIBUTE_TIME_MODIFIED "," G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC,
1706 0,
1707 NULL,
1708 &err);
1709 if (info != NULL) {
1710 g_file_info_get_modification_time (info, result);
1711 g_object_unref (info);
1712 }
1713 else {
1714 char *uri;
1715
1716 uri = g_file_get_uri (file);
1717 g_warning ("could not get modification time for %s: %s", uri, err->message);
1718 g_free (uri);
1719 g_clear_error (&err);
1720 }
1721 }
1722
1723
1724 time_t
_g_file_get_mtime(GFile * file)1725 _g_file_get_mtime (GFile *file)
1726 {
1727 GTimeVal timeval;
1728
1729 _g_file_get_modification_time (file, &timeval);
1730 return (time_t) timeval.tv_sec;
1731 }
1732
1733
1734 int
_g_file_cmp_uris(GFile * a,GFile * b)1735 _g_file_cmp_uris (GFile *a,
1736 GFile *b)
1737 {
1738 return g_file_equal (a, b) ? 0 : 1;
1739 }
1740
1741
1742 int
_g_file_cmp_modification_time(GFile * file_a,GFile * file_b)1743 _g_file_cmp_modification_time (GFile *file_a,
1744 GFile *file_b)
1745 {
1746 GTimeVal timeval_a;
1747 GTimeVal timeval_b;
1748
1749 _g_file_get_modification_time (file_a, &timeval_a);
1750 _g_file_get_modification_time (file_b, &timeval_b);
1751
1752 return _g_time_val_cmp (&timeval_a, &timeval_b);
1753 }
1754
1755
1756 goffset
_g_file_get_size(GFile * file)1757 _g_file_get_size (GFile *file)
1758 {
1759 GFileInfo *info;
1760 GError *err = NULL;
1761 goffset size = 0;
1762
1763 info = g_file_query_info (file, G_FILE_ATTRIBUTE_FILESYSTEM_SIZE, 0, NULL, &err);
1764 if (info != NULL) {
1765 size = g_file_info_get_size (info);
1766 g_object_unref (info);
1767 }
1768 else {
1769 char *uri;
1770
1771 uri = g_file_get_uri (file);
1772 g_warning ("could not get size for %s: %s", uri, err->message);
1773 g_free (uri);
1774 g_clear_error (&err);
1775 }
1776
1777 return size;
1778 }
1779
1780
1781 #define MAX_SYMLINKS 32
1782
1783
1784 static GFile *
resolve_symlinks(GFile * file,GError ** error,int level)1785 resolve_symlinks (GFile *file,
1786 GError **error,
1787 int level)
1788 {
1789 GFile *resolved;
1790 char *path;
1791 char **names;
1792 int i;
1793
1794 if (level > MAX_SYMLINKS) {
1795 char *uri;
1796
1797 uri = g_file_get_uri (file);
1798 *error = g_error_new (G_IO_ERROR, G_IO_ERROR_TOO_MANY_LINKS, "Too many symbolic links for file: %s.", uri);
1799 g_free (uri);
1800
1801 return NULL;
1802 }
1803
1804 path = g_file_get_path (file);
1805 if (path == NULL) {
1806 char *uri;
1807
1808 uri = g_file_get_uri (file);
1809 *error = g_error_new (G_IO_ERROR, G_IO_ERROR_FAILED, "No local pathname for file: %s.", uri);
1810 g_free (uri);
1811
1812 return NULL;
1813 }
1814
1815 resolved = g_file_new_for_path (G_DIR_SEPARATOR_S);
1816
1817 names = g_strsplit (path, G_DIR_SEPARATOR_S, -1);
1818 for (i = 0; names[i] != NULL; i++) {
1819 GFile *child;
1820 GFileInfo *info;
1821 GFile *new_resolved;
1822
1823 if (strcmp (names[i], "") == 0)
1824 continue;
1825
1826 child = g_file_get_child (resolved, names[i]);
1827 info = g_file_query_info (child, G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK "," G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET, 0, NULL, error);
1828 if (info == NULL) {
1829 g_object_unref (child);
1830 g_object_unref (resolved);
1831 resolved = NULL;
1832 break;
1833 }
1834
1835 /* if names[i] isn't a symbolic link add it to the resolved path and continue */
1836
1837 if (! g_file_info_get_is_symlink (info)) {
1838 g_object_unref (info);
1839 g_object_unref (resolved);
1840 resolved = child;
1841 continue;
1842 }
1843
1844 g_object_unref (child);
1845
1846 /* names[i] is a symbolic link */
1847
1848 new_resolved = g_file_resolve_relative_path (resolved, g_file_info_get_symlink_target (info));
1849
1850 g_object_unref (resolved);
1851 g_object_unref (info);
1852
1853 resolved = resolve_symlinks (new_resolved, error, level + 1);
1854
1855 g_object_unref (new_resolved);
1856 }
1857
1858 g_strfreev (names);
1859 g_free (path);
1860
1861 return resolved;
1862 }
1863
1864
1865 GFile *
_g_file_resolve_all_symlinks(GFile * file,GError ** error)1866 _g_file_resolve_all_symlinks (GFile *file,
1867 GError **error)
1868 {
1869 return resolve_symlinks (file, error, 0);
1870 }
1871
1872
1873 GFile *
_g_file_append_prefix(GFile * file,const char * prefix)1874 _g_file_append_prefix (GFile *file,
1875 const char *prefix)
1876 {
1877 char *uri;
1878 char *new_uri;
1879 GFile *new_file;
1880
1881 uri = g_file_get_uri (file);
1882 new_uri = g_strconcat (prefix, uri, NULL);
1883 new_file = g_file_new_for_uri (new_uri);
1884
1885 g_free (new_uri);
1886 g_free (uri);
1887
1888 return new_file;
1889 }
1890
1891
1892 GFile *
_g_file_append_path(GFile * file,const char * path)1893 _g_file_append_path (GFile *file,
1894 const char *path)
1895 {
1896 char *uri;
1897 char *escaped;
1898 char *new_uri;
1899 GFile *new_file;
1900
1901 if (path == NULL)
1902 return g_file_dup (file);
1903
1904 uri = g_file_get_uri (file);
1905 escaped = g_uri_escape_string (path, G_URI_RESERVED_CHARS_ALLOWED_IN_PATH, FALSE);
1906 new_uri = _g_build_uri (uri, escaped, NULL);
1907 new_file = g_file_new_for_uri (new_uri);
1908
1909 g_free (new_uri);
1910 g_free (escaped);
1911 g_free (uri);
1912
1913 return new_file;
1914 }
1915
1916
1917 static gboolean
_g_file_attributes_matches_mask(const char * attributes,const char * mask)1918 _g_file_attributes_matches_mask (const char *attributes,
1919 const char *mask)
1920 {
1921 gboolean matches = FALSE;
1922 char **attributes_v;
1923 char **mask_v;
1924 int i;
1925
1926 attributes_v = g_strsplit (attributes, ",", -1);
1927 mask_v = g_strsplit (mask, ",", -1);
1928 for (i = 0; ! matches && (mask_v[i] != NULL); i++) {
1929 GFileAttributeMatcher *matcher;
1930 int j;
1931
1932 matcher = g_file_attribute_matcher_new (mask_v[i]);
1933 for (j = 0; ! matches && (attributes_v[j] != NULL); j++)
1934 matches = g_file_attribute_matcher_matches (matcher, attributes_v[j]);
1935
1936 g_file_attribute_matcher_unref (matcher);
1937 }
1938
1939 g_strfreev (mask_v);
1940 g_strfreev (attributes_v);
1941
1942 return matches;
1943 }
1944
1945
1946 gboolean
_g_file_attributes_matches(const char * attributes,const char * mask)1947 _g_file_attributes_matches (const char *attributes,
1948 const char *mask)
1949 {
1950 return _g_file_attributes_matches_mask (attributes, mask) || _g_file_attributes_matches_mask (mask, attributes);
1951 }
1952
1953
1954 /* -- _g_file_info_swap_attributes -- */
1955
1956
1957 typedef struct {
1958 GFileAttributeType type;
1959 union {
1960 char *string;
1961 char **stringv;
1962 gboolean boolean;
1963 guint32 uint32;
1964 gint32 int32;
1965 guint64 uint64;
1966 gint64 int64;
1967 gpointer object;
1968 } v;
1969 } _GFileAttributeValue;
1970
1971
1972 static void
_g_file_attribute_value_free(_GFileAttributeValue * attr_value)1973 _g_file_attribute_value_free (_GFileAttributeValue *attr_value)
1974 {
1975 switch (attr_value->type) {
1976 case G_FILE_ATTRIBUTE_TYPE_STRING:
1977 case G_FILE_ATTRIBUTE_TYPE_BYTE_STRING:
1978 g_free (attr_value->v.string);
1979 break;
1980 /* FIXME: add if glib >= 2.22
1981 case G_FILE_ATTRIBUTE_TYPE_STRINGV:
1982 g_strfreev (attr_value->v.stringv);
1983 break;
1984 */
1985 case G_FILE_ATTRIBUTE_TYPE_OBJECT:
1986 g_object_unref (attr_value->v.object);
1987 break;
1988 default:
1989 break;
1990 }
1991
1992 g_free (attr_value);
1993 }
1994
1995
1996 static _GFileAttributeValue *
_g_file_info_get_value(GFileInfo * info,const char * attr)1997 _g_file_info_get_value (GFileInfo *info,
1998 const char *attr)
1999 {
2000 _GFileAttributeValue *attr_value;
2001 GFileAttributeType type;
2002 gpointer value;
2003 GFileAttributeStatus status;
2004
2005 attr_value = g_new (_GFileAttributeValue, 1);
2006 attr_value->type = G_FILE_ATTRIBUTE_TYPE_INVALID;
2007
2008 if (! g_file_info_get_attribute_data (info, attr, &type, &value, &status))
2009 return attr_value;
2010
2011 attr_value->type = type;
2012 switch (type) {
2013 case G_FILE_ATTRIBUTE_TYPE_INVALID:
2014 break;
2015 case G_FILE_ATTRIBUTE_TYPE_STRING:
2016 case G_FILE_ATTRIBUTE_TYPE_BYTE_STRING:
2017 attr_value->v.string = g_strdup ((char *) value);
2018 break;
2019 /* FIXME: add if glib >= 2.22
2020 case G_FILE_ATTRIBUTE_TYPE_STRINGV:
2021 attr_value->v.stringv = g_strdupv ((char **) value);
2022 break;
2023 */
2024 case G_FILE_ATTRIBUTE_TYPE_BOOLEAN:
2025 attr_value->v.boolean = * ((gboolean *) value);
2026 break;
2027 case G_FILE_ATTRIBUTE_TYPE_UINT32:
2028 attr_value->v.uint32 = * ((guint32 *) value);
2029 break;
2030 case G_FILE_ATTRIBUTE_TYPE_INT32:
2031 attr_value->v.int32 = * ((gint32 *) value);
2032 break;
2033 case G_FILE_ATTRIBUTE_TYPE_UINT64:
2034 attr_value->v.uint64 = * ((guint64 *) value);
2035 break;
2036 case G_FILE_ATTRIBUTE_TYPE_INT64:
2037 attr_value->v.int64 = * ((gint64 *) value);
2038 break;
2039 case G_FILE_ATTRIBUTE_TYPE_OBJECT:
2040 attr_value->v.object = g_object_ref ((GObject *) value);
2041 break;
2042 default:
2043 g_warning ("unknown attribute type: %d", type);
2044 break;
2045 }
2046
2047 return attr_value;
2048 }
2049
2050
2051 static void
_g_file_info_set_value(GFileInfo * info,const char * attr,_GFileAttributeValue * attr_value)2052 _g_file_info_set_value (GFileInfo *info,
2053 const char *attr,
2054 _GFileAttributeValue *attr_value)
2055 {
2056 gpointer value = NULL;
2057
2058 if (attr_value->type == G_FILE_ATTRIBUTE_TYPE_INVALID)
2059 return;
2060
2061 switch (attr_value->type) {
2062 case G_FILE_ATTRIBUTE_TYPE_STRING:
2063 case G_FILE_ATTRIBUTE_TYPE_BYTE_STRING:
2064 value = attr_value->v.string;
2065 break;
2066 /* FIXME: add if glib >= 2.22
2067 case G_FILE_ATTRIBUTE_TYPE_STRINGV:
2068 value = attr_value->v.stringv;
2069 break;
2070 */
2071 case G_FILE_ATTRIBUTE_TYPE_BOOLEAN:
2072 value = &attr_value->v.boolean;
2073 break;
2074 case G_FILE_ATTRIBUTE_TYPE_UINT32:
2075 value = &attr_value->v.uint32;
2076 break;
2077 case G_FILE_ATTRIBUTE_TYPE_INT32:
2078 value = &attr_value->v.int32;
2079 break;
2080 case G_FILE_ATTRIBUTE_TYPE_UINT64:
2081 value = &attr_value->v.uint64;
2082 break;
2083 case G_FILE_ATTRIBUTE_TYPE_INT64:
2084 value = &attr_value->v.int64;
2085 break;
2086 case G_FILE_ATTRIBUTE_TYPE_OBJECT:
2087 value = attr_value->v.object;
2088 break;
2089 default:
2090 g_warning ("Unknown attribute type: %d", attr_value->type);
2091 break;
2092 }
2093
2094 g_file_info_set_attribute (info, attr, attr_value->type, value);
2095 }
2096
2097
2098 void
_g_file_info_swap_attributes(GFileInfo * info,const char * attr1,const char * attr2)2099 _g_file_info_swap_attributes (GFileInfo *info,
2100 const char *attr1,
2101 const char *attr2)
2102 {
2103 _GFileAttributeValue *value1;
2104 _GFileAttributeValue *value2;
2105
2106 value1 = _g_file_info_get_value (info, attr1);
2107 value2 = _g_file_info_get_value (info, attr2);
2108
2109 _g_file_info_set_value (info, attr1, value2);
2110 _g_file_info_set_value (info, attr2, value1);
2111
2112 _g_file_attribute_value_free (value1);
2113 _g_file_attribute_value_free (value2);
2114 }
2115
2116
2117 gboolean
_g_mime_type_is_image(const char * mime_type)2118 _g_mime_type_is_image (const char *mime_type)
2119 {
2120 g_return_val_if_fail (mime_type != NULL, FALSE);
2121
2122 /* Valid image mime types:
2123 1. All *image* types,
2124 2. application/x-crw
2125 This is a RAW photo file, which for some reason
2126 uses an "application" prefix instead of "image".
2127 */
2128
2129 return (g_content_type_is_a (mime_type, "image/*")
2130 || (strcmp (mime_type, "application/x-crw") == 0));
2131 }
2132
2133
2134 gboolean
_g_mime_type_is_video(const char * mime_type)2135 _g_mime_type_is_video (const char *mime_type)
2136 {
2137 g_return_val_if_fail (mime_type != NULL, FALSE);
2138
2139 return (g_content_type_is_a (mime_type, "video/*")
2140 || (strcmp (mime_type, "application/ogg") == 0)
2141 || (strcmp (mime_type, "application/vnd.rn-realmedia") == 0));
2142 }
2143
2144
2145 gboolean
_g_mime_type_is_audio(const char * mime_type)2146 _g_mime_type_is_audio (const char *mime_type)
2147 {
2148 g_return_val_if_fail (mime_type != NULL, FALSE);
2149
2150 return g_content_type_is_a (mime_type, "audio/*");
2151 }
2152
2153
2154 gboolean
_g_volume_equal(GVolume * v1,GVolume * v2)2155 _g_volume_equal (GVolume *v1,
2156 GVolume *v2)
2157 {
2158 char *id1;
2159 char *id2;
2160 gboolean result;
2161
2162 id1 = g_volume_get_identifier (v1, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
2163 id2 = g_volume_get_identifier (v2, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
2164 result = g_strcmp0 (id1, id2) == 0;
2165
2166 g_free (id1);
2167 g_free (id2);
2168
2169 return result;
2170 }
2171
2172
2173 gboolean
_g_drive_equal(GDrive * d1,GDrive * d2)2174 _g_drive_equal (GDrive *d1,
2175 GDrive *d2)
2176 {
2177 char *id1;
2178 char *id2;
2179 gboolean result;
2180
2181 id1 = g_drive_get_identifier (d1, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
2182 id2 = g_drive_get_identifier (d2, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
2183 result = g_strcmp0 (id1, id2) == 0;
2184
2185 g_free (id1);
2186 g_free (id2);
2187
2188 return result;
2189 }
2190
2191
2192 char *
_g_make_temp_directory(void)2193 _g_make_temp_directory (void)
2194 {
2195 char *template;
2196
2197 template = g_strconcat (g_get_tmp_dir (), "/goobox-XXXXXX", NULL);
2198 g_assert (mkdtemp (template) != NULL);
2199
2200 return template;
2201 }
2202
2203
2204 /* this is totem_time_to_string renamed, thanks to the authors :) */
2205 char *
_g_format_duration_for_display(gint64 msecs)2206 _g_format_duration_for_display (gint64 msecs)
2207 {
2208 int sec, min, hour, _time;
2209
2210 _time = (int) (msecs / 1000);
2211 sec = _time % 60;
2212 _time = _time - sec;
2213 min = (_time % (60*60)) / 60;
2214 _time = _time - (min * 60);
2215 hour = _time / (60*60);
2216
2217 if (hour > 0)
2218 {
2219 /* hour:minutes:seconds */
2220 /* Translators: This is a time format, like "9:05:02" for 9
2221 * hours, 5 minutes, and 2 seconds. You may change ":" to
2222 * the separator that your locale uses or use "%Id" instead
2223 * of "%d" if your locale uses localized digits.
2224 */
2225 return g_strdup_printf (C_("long time format", "%d∶%02d∶%02d"), hour, min, sec);
2226 }
2227
2228 /* minutes:seconds */
2229 /* Translators: This is a time format, like "5:02" for 5
2230 * minutes and 2 seconds. You may change ":" to the
2231 * separator that your locale uses or use "%Id" instead of
2232 * "%d" if your locale uses localized digits.
2233 */
2234 return g_strdup_printf (C_("short time format", "%d∶%02d"), min, sec);
2235 }
2236
2237
2238 void
_g_toggle_action_activated(GSimpleAction * action,GVariant * parameter,gpointer data)2239 _g_toggle_action_activated (GSimpleAction *action,
2240 GVariant *parameter,
2241 gpointer data)
2242 {
2243 GVariant *state;
2244
2245 state = g_action_get_state (G_ACTION (action));
2246 g_action_change_state (G_ACTION (action), g_variant_new_boolean (! g_variant_get_boolean (state)));
2247
2248 g_variant_unref (state);
2249 }
2250