1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2
3 /*
4 * File-Roller
5 *
6 * Copyright (C) 2005 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 <ctype.h>
24 #include <string.h>
25 #include <stdio.h>
26 #include <glib.h>
27 #include <glib/gi18n.h>
28 #include <glib/gprintf.h>
29 #include <glib-object.h>
30 #include "glib-utils.h"
31
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 return (object != NULL) ? g_object_ref (object) : NULL;
43 }
44
45
46 void
_g_object_unref(gpointer object)47 _g_object_unref (gpointer object)
48 {
49 if (object != NULL)
50 g_object_unref (object);
51 }
52
53
54 void
_g_clear_object(gpointer p)55 _g_clear_object (gpointer p)
56 {
57 g_clear_object ((GObject **) p);
58 }
59
60
61 GList *
_g_object_list_ref(GList * list)62 _g_object_list_ref (GList *list)
63 {
64 GList *new_list;
65
66 if (list == NULL)
67 return NULL;
68
69 new_list = g_list_copy (list);
70 g_list_foreach (new_list, (GFunc) g_object_ref, NULL);
71
72 return new_list;
73 }
74
75
76 void
_g_object_list_unref(GList * list)77 _g_object_list_unref (GList *list)
78 {
79 g_list_foreach (list, (GFunc) g_object_unref, NULL);
80 g_list_free (list);
81 }
82
83 /* enum */
84
85
86 GEnumValue *
_g_enum_type_get_value(GType enum_type,int value)87 _g_enum_type_get_value (GType enum_type,
88 int value)
89 {
90 GEnumClass *class;
91 GEnumValue *enum_value;
92
93 class = G_ENUM_CLASS (g_type_class_ref (enum_type));
94 enum_value = g_enum_get_value (class, value);
95 g_type_class_unref (class);
96
97 return enum_value;
98 }
99
100
101 GEnumValue *
_g_enum_type_get_value_by_nick(GType enum_type,const char * nick)102 _g_enum_type_get_value_by_nick (GType enum_type,
103 const char *nick)
104 {
105 GEnumClass *class;
106 GEnumValue *enum_value;
107
108 class = G_ENUM_CLASS (g_type_class_ref (enum_type));
109 enum_value = g_enum_get_value_by_nick (class, nick);
110 g_type_class_unref (class);
111
112 return enum_value;
113 }
114
115
116 /* error */
117
118
119 void
_g_error_free(GError * error)120 _g_error_free (GError *error)
121 {
122 if (error != NULL)
123 g_error_free (error);
124 }
125
126
127 /* string */
128
129
130 gboolean
_g_strchrs(const char * str,const char * chars)131 _g_strchrs (const char *str,
132 const char *chars)
133 {
134 const char *c;
135 for (c = chars; *c != '\0'; c++)
136 if (strchr (str, *c) != NULL)
137 return TRUE;
138 return FALSE;
139 }
140
141
142 char *
_g_str_substitute(const char * str,const char * from_str,const char * to_str)143 _g_str_substitute (const char *str,
144 const char *from_str,
145 const char *to_str)
146 {
147 char **tokens;
148 int i;
149 GString *gstr;
150
151 if (str == NULL)
152 return NULL;
153
154 if (from_str == NULL)
155 return g_strdup (str);
156
157 if (strcmp (str, from_str) == 0)
158 return g_strdup (to_str);
159
160 tokens = g_strsplit (str, from_str, -1);
161
162 gstr = g_string_new (NULL);
163 for (i = 0; tokens[i] != NULL; i++) {
164 gstr = g_string_append (gstr, tokens[i]);
165 if ((to_str != NULL) && (tokens[i+1] != NULL))
166 gstr = g_string_append (gstr, to_str);
167 }
168
169 return g_string_free (gstr, FALSE);
170 }
171
172
173 gboolean
_g_str_equal(const char * s1,const char * s2)174 _g_str_equal (const char *s1,
175 const char *s2)
176 {
177 return g_strcmp0 (s1, s2) == 0;
178 }
179
180
181 /* -- _g_str_escape_full -- */
182
183
184 /* counts how many characters to escape in @str. */
185 static int
count_chars_to_escape(const char * str,const char * meta_chars)186 count_chars_to_escape (const char *str,
187 const char *meta_chars)
188 {
189 int meta_chars_n = strlen (meta_chars);
190 const char *s;
191 int n = 0;
192
193 for (s = str; *s != 0; s++) {
194 int i;
195 for (i = 0; i < meta_chars_n; i++)
196 if (*s == meta_chars[i]) {
197 n++;
198 break;
199 }
200 }
201
202 return n;
203 }
204
205
206 char *
_g_str_escape_full(const char * str,const char * meta_chars,const char prefix,const char postfix)207 _g_str_escape_full (const char *str,
208 const char *meta_chars,
209 const char prefix,
210 const char postfix)
211 {
212 int meta_chars_n = strlen (meta_chars);
213 char *escaped;
214 int i, new_l, extra_chars = 0;
215 const char *s;
216 char *t;
217
218 if (str == NULL)
219 return NULL;
220
221 if (prefix)
222 extra_chars++;
223 if (postfix)
224 extra_chars++;
225
226 new_l = strlen (str) + (count_chars_to_escape (str, meta_chars) * extra_chars);
227 escaped = g_malloc (new_l + 1);
228
229 s = str;
230 t = escaped;
231 while (*s) {
232 gboolean is_bad = FALSE;
233 for (i = 0; (i < meta_chars_n) && !is_bad; i++)
234 is_bad = (*s == meta_chars[i]);
235 if (is_bad && prefix)
236 *t++ = prefix;
237 *t++ = *s++;
238 if (is_bad && postfix)
239 *t++ = postfix;
240 }
241 *t = 0;
242
243 return escaped;
244 }
245
246
247 /* escape with backslash the string @str. */
248 char *
_g_str_escape(const char * str,const char * meta_chars)249 _g_str_escape (const char *str,
250 const char *meta_chars)
251 {
252 return _g_str_escape_full (str, meta_chars, '\\', 0);
253 }
254
255
256 /* escape with backslash the file name. */
257 char *
_g_str_shell_escape(const char * filename)258 _g_str_shell_escape (const char *filename)
259 {
260 return _g_str_escape (filename, "$'`\"\\!?* ()[]&|:;<>#");
261 }
262
263
264 char *
_g_strdup_with_max_size(const char * s,int max_size)265 _g_strdup_with_max_size (const char *s,
266 int max_size)
267 {
268 char *result;
269 int l = strlen (s);
270
271 if (l > max_size) {
272 char *first_half;
273 char *second_half;
274 int offset;
275 int half_max_size = max_size / 2 + 1;
276
277 first_half = g_strndup (s, half_max_size);
278 offset = half_max_size + l - max_size;
279 second_half = g_strndup (s + offset, half_max_size);
280
281 result = g_strconcat (first_half, "...", second_half, NULL);
282
283 g_free (first_half);
284 g_free (second_half);
285 } else
286 result = g_strdup (s);
287
288 return result;
289 }
290
291
292 const char *
_g_str_eat_spaces(const char * line)293 _g_str_eat_spaces (const char *line)
294 {
295 if (line == NULL)
296 return NULL;
297 while ((*line == ' ') && (*line != 0))
298 line++;
299 return line;
300 }
301
302
303 const char *
_g_str_eat_void_chars(const char * line)304 _g_str_eat_void_chars (const char *line)
305 {
306 if (line == NULL)
307 return NULL;
308 while (((*line == ' ') || (*line == '\t')) && (*line != 0))
309 line++;
310 return line;
311 }
312
313
314 char **
_g_str_split_line(const char * line,int n_fields)315 _g_str_split_line (const char *line,
316 int n_fields)
317 {
318 char **fields;
319 const char *scan, *field_end;
320 int i;
321
322 fields = g_new0 (char *, n_fields + 1);
323 fields[n_fields] = NULL;
324
325 scan = _g_str_eat_spaces (line);
326 for (i = 0; i < n_fields; i++) {
327 if (scan == NULL) {
328 fields[i] = NULL;
329 continue;
330 }
331 field_end = strchr (scan, ' ');
332 if (field_end != NULL) {
333 fields[i] = g_strndup (scan, field_end - scan);
334 scan = _g_str_eat_spaces (field_end);
335 }
336 }
337
338 return fields;
339 }
340
341
342 const char *
_g_str_get_last_field(const char * line,int last_field)343 _g_str_get_last_field (const char *line,
344 int last_field)
345 {
346 const char *field;
347 int i;
348
349 if (line == NULL)
350 return NULL;
351
352 last_field--;
353 field = _g_str_eat_spaces (line);
354 for (i = 0; i < last_field; i++) {
355 if (field == NULL)
356 return NULL;
357 field = strchr (field, ' ');
358 field = _g_str_eat_spaces (field);
359 }
360
361 return field;
362 }
363
364
365 GHashTable *static_strings = NULL;
366
367
368 const char *
_g_str_get_static(const char * s)369 _g_str_get_static (const char *s)
370 {
371 const char *result;
372
373 if (s == NULL)
374 return NULL;
375
376 if (static_strings == NULL)
377 static_strings = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
378
379 if (! g_hash_table_lookup_extended (static_strings, s, (gpointer*) &result, NULL)) {
380 result = g_strdup (s);
381 g_hash_table_insert (static_strings,
382 (gpointer) result,
383 GINT_TO_POINTER (1));
384 }
385
386 return result;
387 }
388
389
390 /* utf8 */
391
392
393 gboolean
_g_utf8_all_spaces(const char * text)394 _g_utf8_all_spaces (const char *text)
395 {
396 const char *scan;
397
398 if (text == NULL)
399 return TRUE;
400
401 for (scan = text; *scan != 0; scan = g_utf8_next_char (scan)) {
402 gunichar c = g_utf8_get_char (scan);
403 if (! g_unichar_isspace (c))
404 return FALSE;
405 }
406
407 return TRUE;
408 }
409
410
411 /* string vector */
412
413
414 char **
_g_strv_prepend(char ** str_array,const char * str)415 _g_strv_prepend (char **str_array,
416 const char *str)
417 {
418 char **result;
419 int i;
420 int j;
421
422 result = g_new (char *, g_strv_length (str_array) + 1);
423 i = 0;
424 result[i++] = g_strdup (str);
425 for (j = 0; str_array[j] != NULL; j++)
426 result[i++] = g_strdup (str_array[j]);
427 result[i] = NULL;
428
429 return result;
430 }
431
432
433 gboolean
_g_strv_remove(char ** str_array,const char * str)434 _g_strv_remove (char **str_array,
435 const char *str)
436 {
437 int i;
438 int j;
439
440 if (str == NULL)
441 return FALSE;
442
443 for (i = 0; str_array[i] != NULL; i++)
444 if (strcmp (str_array[i], str) == 0)
445 break;
446
447 if (str_array[i] == NULL)
448 return FALSE;
449
450 for (j = i; str_array[j] != NULL; j++)
451 str_array[j] = str_array[j + 1];
452
453 return TRUE;
454 }
455
456
457 /* string list */
458
459
460 void
_g_string_list_free(GList * path_list)461 _g_string_list_free (GList *path_list)
462 {
463 if (path_list == NULL)
464 return;
465 g_list_foreach (path_list, (GFunc) g_free, NULL);
466 g_list_free (path_list);
467 }
468
469
470 GList *
_g_string_list_dup(GList * path_list)471 _g_string_list_dup (GList *path_list)
472 {
473 GList *new_list = NULL;
474 GList *scan;
475
476 for (scan = path_list; scan; scan = scan->next)
477 new_list = g_list_prepend (new_list, g_strdup (scan->data));
478
479 return g_list_reverse (new_list);
480 }
481
482
483 /* GPtrArray */
484
485
486 GPtrArray *
_g_ptr_array_copy(GPtrArray * array)487 _g_ptr_array_copy (GPtrArray *array)
488 {
489 GPtrArray *new_array;
490
491 if (array == NULL)
492 return NULL;
493
494 new_array = g_ptr_array_sized_new (array->len);
495 memcpy (new_array->pdata, array->pdata, array->len * sizeof (gpointer));
496 new_array->len = array->len;
497
498 return new_array;
499 }
500
501
502 void
_g_ptr_array_free_full(GPtrArray * array,GFunc free_func,gpointer user_data)503 _g_ptr_array_free_full (GPtrArray *array,
504 GFunc free_func,
505 gpointer user_data)
506 {
507 g_ptr_array_foreach (array, free_func, user_data);
508 g_ptr_array_free (array, TRUE);
509 }
510
511
512 void
_g_ptr_array_reverse(GPtrArray * array)513 _g_ptr_array_reverse (GPtrArray *array)
514 {
515 int i, j;
516 gpointer tmp;
517
518 for (i = 0; i < array->len / 2; i++) {
519 j = array->len - i - 1;
520 tmp = g_ptr_array_index (array, i);
521 g_ptr_array_index (array, i) = g_ptr_array_index (array, j);
522 g_ptr_array_index (array, j) = tmp;
523 }
524 }
525
526
527 int
_g_ptr_array_binary_search(GPtrArray * array,gpointer value,GCompareFunc func)528 _g_ptr_array_binary_search (GPtrArray *array,
529 gpointer value,
530 GCompareFunc func)
531 {
532 int l, r, p, cmp = -1;
533
534 l = 0;
535 r = array->len;
536 while (l < r) {
537 p = l + ((r - l) / 2);
538 cmp = func(value, &g_ptr_array_index (array, p));
539 if (cmp == 0)
540 return p;
541 else if (cmp < 0)
542 r = p;
543 else
544 l = p + 1;
545 }
546
547 return -1;
548 }
549
550
551 /* GRegex */
552
553
554 gboolean
_g_regexp_matchv(GRegex ** regexps,const char * string,GRegexMatchFlags match_options)555 _g_regexp_matchv (GRegex **regexps,
556 const char *string,
557 GRegexMatchFlags match_options)
558 {
559 gboolean matched;
560 int i;
561
562 if ((regexps == NULL) || (regexps[0] == NULL))
563 return TRUE;
564
565 if (string == NULL)
566 return FALSE;
567
568 matched = FALSE;
569 for (i = 0; regexps[i] != NULL; i++)
570 if (g_regex_match (regexps[i], string, match_options, NULL)) {
571 matched = TRUE;
572 break;
573 }
574
575 return matched;
576 }
577
578
579 void
_g_regexp_freev(GRegex ** regexps)580 _g_regexp_freev (GRegex **regexps)
581 {
582 int i;
583
584 if (regexps == NULL)
585 return;
586
587 for (i = 0; regexps[i] != NULL; i++)
588 g_regex_unref (regexps[i]);
589 g_free (regexps);
590 }
591
592
593 /* -- _g_regexp_get_patternv -- */
594
595
596 static const char *
_g_utf8_strstr(const char * haystack,const char * needle)597 _g_utf8_strstr (const char *haystack,
598 const char *needle)
599 {
600 const char *s;
601 gsize i;
602 gsize haystack_len = g_utf8_strlen (haystack, -1);
603 gsize needle_len = g_utf8_strlen (needle, -1);
604 int needle_size = strlen (needle);
605
606 s = haystack;
607 for (i = 0; i <= haystack_len - needle_len; i++) {
608 if (strncmp (s, needle, needle_size) == 0)
609 return s;
610 s = g_utf8_next_char(s);
611 }
612
613 return NULL;
614 }
615
616
617 static char **
_g_utf8_strsplit(const char * string,const char * delimiter,int max_tokens)618 _g_utf8_strsplit (const char *string,
619 const char *delimiter,
620 int max_tokens)
621 {
622 GSList *string_list = NULL, *slist;
623 char **str_array;
624 const char *s;
625 guint n = 0;
626 const char *remainder;
627
628 g_return_val_if_fail (string != NULL, NULL);
629 g_return_val_if_fail (delimiter != NULL, NULL);
630 g_return_val_if_fail (delimiter[0] != '\0', NULL);
631
632 if (max_tokens < 1)
633 max_tokens = G_MAXINT;
634
635 remainder = string;
636 s = _g_utf8_strstr (remainder, delimiter);
637 if (s != NULL) {
638 gsize delimiter_size = strlen (delimiter);
639
640 while (--max_tokens && (s != NULL)) {
641 gsize size = s - remainder;
642 char *new_string;
643
644 new_string = g_new (char, size + 1);
645 strncpy (new_string, remainder, size);
646 new_string[size] = 0;
647
648 string_list = g_slist_prepend (string_list, new_string);
649 n++;
650 remainder = s + delimiter_size;
651 s = _g_utf8_strstr (remainder, delimiter);
652 }
653 }
654 if (*string) {
655 n++;
656 string_list = g_slist_prepend (string_list, g_strdup (remainder));
657 }
658
659 str_array = g_new (char*, n + 1);
660
661 str_array[n--] = NULL;
662 for (slist = string_list; slist; slist = slist->next)
663 str_array[n--] = slist->data;
664
665 g_slist_free (string_list);
666
667 return str_array;
668 }
669
670
671 static char*
g_utf8_strchug(char * string)672 g_utf8_strchug (char *string)
673 {
674 char *scan;
675 gunichar c;
676
677 g_return_val_if_fail (string != NULL, NULL);
678
679 scan = string;
680 c = g_utf8_get_char (scan);
681 while (g_unichar_isspace (c)) {
682 scan = g_utf8_next_char (scan);
683 c = g_utf8_get_char (scan);
684 }
685
686 memmove (string, scan, strlen (scan) + 1);
687
688 return string;
689 }
690
691
692 static char*
g_utf8_strchomp(char * string)693 g_utf8_strchomp (char *string)
694 {
695 char *scan;
696 gsize len;
697
698 g_return_val_if_fail (string != NULL, NULL);
699
700 len = g_utf8_strlen (string, -1);
701
702 if (len == 0)
703 return string;
704
705 scan = g_utf8_offset_to_pointer (string, len - 1);
706
707 while (len--) {
708 gunichar c = g_utf8_get_char (scan);
709 if (g_unichar_isspace (c))
710 *scan = '\0';
711 else
712 break;
713 scan = g_utf8_find_prev_char (string, scan);
714 }
715
716 return string;
717 }
718
719
720 #define g_utf8_strstrip(string) g_utf8_strchomp (g_utf8_strchug (string))
721
722
723 char **
_g_regexp_get_patternv(const char * pattern_string)724 _g_regexp_get_patternv (const char *pattern_string)
725 {
726 char **patterns;
727 int i;
728
729 if (pattern_string == NULL)
730 return NULL;
731
732 patterns = _g_utf8_strsplit (pattern_string, ";", MAX_PATTERNS);
733 for (i = 0; patterns[i] != NULL; i++) {
734 char *p1, *p2;
735
736 p1 = g_utf8_strstrip (patterns[i]);
737 p2 = _g_str_substitute (p1, ".", "\\.");
738 patterns[i] = _g_str_substitute (p2, "*", ".*");
739
740 g_free (p2);
741 g_free (p1);
742 }
743
744 return patterns;
745 }
746
747
748 GRegex **
_g_regexp_split_from_patterns(const char * pattern_string,GRegexCompileFlags compile_options)749 _g_regexp_split_from_patterns (const char *pattern_string,
750 GRegexCompileFlags compile_options)
751 {
752 char **patterns;
753 GRegex **regexps;
754 int i;
755
756 patterns = _g_regexp_get_patternv (pattern_string);
757 if (patterns == NULL)
758 return NULL;
759
760 regexps = g_new0 (GRegex*, g_strv_length (patterns) + 1);
761 for (i = 0; patterns[i] != NULL; i++)
762 regexps[i] = g_regex_new (patterns[i],
763 G_REGEX_OPTIMIZE | compile_options,
764 G_REGEX_MATCH_NOTEMPTY,
765 NULL);
766 g_strfreev (patterns);
767
768 return regexps;
769 }
770
771
772 /* time */
773
774
775 char *
_g_time_to_string(time_t time)776 _g_time_to_string (time_t time)
777 {
778 struct tm *tm;
779 char s_time[256];
780 char *locale_format = NULL;
781 char *time_utf8;
782
783 tm = localtime (&time);
784 /* This is the time format used in the "Date Modified" column and
785 * in the Properties dialog. See the man page of strftime for an
786 * explanation of the values. */
787 locale_format = g_locale_from_utf8 (_("%d %B %Y, %H:%M"), -1, NULL, NULL, NULL);
788 strftime (s_time, sizeof (s_time) - 1, locale_format, tm);
789 g_free (locale_format);
790 time_utf8 = g_locale_to_utf8 (s_time, -1, NULL, NULL, NULL);
791
792 return time_utf8;
793 }
794
795
796 /* uri/path/filename */
797
798
799 const char *
_g_uri_get_home(void)800 _g_uri_get_home (void)
801 {
802 static char *home_uri = NULL;
803 if (home_uri == NULL)
804 home_uri = g_filename_to_uri (g_get_home_dir (), NULL, NULL);
805 return home_uri;
806 }
807
808
809 char *
_g_uri_get_home_relative(const char * partial_uri)810 _g_uri_get_home_relative (const char *partial_uri)
811 {
812 return g_strconcat (_g_uri_get_home (),
813 "/",
814 partial_uri,
815 NULL);
816 }
817
818
819 const char *
_g_uri_remove_host(const char * uri)820 _g_uri_remove_host (const char *uri)
821 {
822 const char *idx, *sep;
823
824 if (uri == NULL)
825 return NULL;
826
827 idx = strstr (uri, "://");
828 if (idx == NULL)
829 return uri;
830 idx += 3;
831 if (*idx == '\0')
832 return "/";
833 sep = strstr (idx, "/");
834 if (sep == NULL)
835 return idx;
836 return sep;
837 }
838
839
840 char *
_g_uri_get_host(const char * uri)841 _g_uri_get_host (const char *uri)
842 {
843 const char *idx;
844
845 idx = strstr (uri, "://");
846 if (idx == NULL)
847 return NULL;
848 idx = strstr (idx + 3, "/");
849 if (idx == NULL)
850 return NULL;
851 return g_strndup (uri, (idx - uri));
852 }
853
854
855 char *
_g_uri_get_root(const char * uri)856 _g_uri_get_root (const char *uri)
857 {
858 char *host;
859 char *root;
860
861 host = _g_uri_get_host (uri);
862 if (host == NULL)
863 return NULL;
864 root = g_strconcat (host, "/", NULL);
865 g_free (host);
866
867 return root;
868 }
869
870
871 int
_g_uri_cmp(const char * uri1,const char * uri2)872 _g_uri_cmp (const char *uri1,
873 const char *uri2)
874 {
875 return g_strcmp0 (uri1, uri2);
876 }
877
878
879 /* like g_path_get_basename but does not warn about NULL and does not
880 * alloc a new string. */
881 const gchar *
_g_path_get_basename(const gchar * file_name)882 _g_path_get_basename (const gchar *file_name)
883 {
884 register char *base;
885 register gssize last_char;
886
887 if (file_name == NULL)
888 return NULL;
889
890 if (file_name[0] == '\0')
891 return "";
892
893 last_char = strlen (file_name) - 1;
894
895 if (file_name [last_char] == G_DIR_SEPARATOR)
896 return "";
897
898 base = g_utf8_strrchr (file_name, -1, G_DIR_SEPARATOR);
899 if (! base)
900 return file_name;
901
902 return base + 1;
903 }
904
905
906 char *
_g_path_get_dir_name(const gchar * path)907 _g_path_get_dir_name (const gchar *path)
908 {
909 register gssize base;
910 register gssize last_char;
911
912 if (path == NULL)
913 return NULL;
914
915 if (path[0] == '\0')
916 return g_strdup ("");
917
918 last_char = strlen (path) - 1;
919 if (path[last_char] == G_DIR_SEPARATOR)
920 last_char--;
921
922 base = last_char;
923 while ((base >= 0) && (path[base] != G_DIR_SEPARATOR))
924 base--;
925
926 return g_strndup (path + base + 1, last_char - base);
927 }
928
929
930 gchar *
_g_path_remove_level(const gchar * path)931 _g_path_remove_level (const gchar *path)
932 {
933 int p;
934 const char *ptr = path;
935 char *new_path;
936
937 if (path == NULL)
938 return NULL;
939
940 p = strlen (path) - 1;
941 if (p < 0)
942 return NULL;
943
944 /* ignore the first slash if it's the last character,
945 * this way /a/b/ is treated as /a/b */
946
947 if ((ptr[p] == '/') && (p > 0))
948 p--;
949
950 while ((p > 0) && (ptr[p] != '/'))
951 p--;
952 if ((p == 0) && (ptr[p] == '/'))
953 p++;
954 new_path = g_strndup (path, (guint)p);
955
956 return new_path;
957 }
958
959
960 char *
_g_path_remove_ending_separator(const char * path)961 _g_path_remove_ending_separator (const char *path)
962 {
963 gint len, copy_len;
964
965 if (path == NULL)
966 return NULL;
967
968 copy_len = len = strlen (path);
969 if ((len > 1) && (path[len - 1] == '/'))
970 copy_len--;
971
972 return g_strndup (path, copy_len);
973 }
974
975
976 char *
_g_path_remove_extension(const gchar * path)977 _g_path_remove_extension (const gchar *path)
978 {
979 const char *ext;
980
981 if (path == NULL)
982 return NULL;
983
984 ext = _g_filename_get_extension (path);
985 if (ext == NULL)
986 return g_strdup (path);
987 else
988 return g_strndup (path, strlen (path) - strlen (ext));
989 }
990
991
992 char *
_g_path_remove_first_extension(const gchar * path)993 _g_path_remove_first_extension (const gchar *path)
994 {
995 const char *ext;
996
997 if (path == NULL)
998 return NULL;
999
1000 ext = strrchr (path, '.');
1001 if (ext == NULL)
1002 return g_strdup (path);
1003 else
1004 return g_strndup (path, strlen (path) - strlen (ext));
1005 }
1006
1007
1008 /* Check whether the dirname is contained in filename */
1009 gboolean
_g_path_is_parent_of(const char * dirname,const char * filename)1010 _g_path_is_parent_of (const char *dirname,
1011 const char *filename)
1012 {
1013 int dirname_l, filename_l, separator_position;
1014
1015 if ((dirname == NULL) || (filename == NULL))
1016 return FALSE;
1017
1018 dirname_l = strlen (dirname);
1019 filename_l = strlen (filename);
1020
1021 if ((dirname_l == filename_l + 1)
1022 && (dirname[dirname_l - 1] == '/'))
1023 return FALSE;
1024
1025 if ((filename_l == dirname_l + 1)
1026 && (filename[filename_l - 1] == '/'))
1027 return FALSE;
1028
1029 if (dirname[dirname_l - 1] == '/')
1030 separator_position = dirname_l - 1;
1031 else
1032 separator_position = dirname_l;
1033
1034 return ((filename_l > dirname_l)
1035 && (strncmp (dirname, filename, dirname_l) == 0)
1036 && (filename[separator_position] == '/'));
1037 }
1038
1039
1040 const char *
_g_path_get_relative_basename(const char * path,const char * base_dir,gboolean junk_paths)1041 _g_path_get_relative_basename (const char *path,
1042 const char *base_dir,
1043 gboolean junk_paths)
1044 {
1045 int base_dir_len;
1046 const char *base_path;
1047
1048 if (junk_paths)
1049 return _g_path_get_basename (path);
1050
1051 if (base_dir == NULL)
1052 return (path[0] == '/') ? path + 1 : path;
1053
1054 base_dir_len = strlen (base_dir);
1055 if (strlen (path) < base_dir_len)
1056 return NULL;
1057
1058 base_path = path + base_dir_len;
1059 if (path[0] != '/')
1060 base_path -= 1;
1061
1062 return base_path;
1063 }
1064
1065
1066 #define ISDOT(c) ((c) == '.')
1067 #define ISSLASH(c) ((c) == '/')
1068
1069
1070 static const char *
sanitize_filename(const char * file_name)1071 sanitize_filename (const char *file_name)
1072 {
1073 size_t prefix_len;
1074 char const *p;
1075
1076 if (file_name == NULL)
1077 return NULL;
1078
1079 prefix_len = 0;
1080 for (p = file_name; *p; ) {
1081 if (ISDOT (p[0]) && ISDOT (p[1]) && (ISSLASH (p[2]) || !p[2]))
1082 return NULL;
1083
1084 do {
1085 char c = *p++;
1086 if (ISSLASH (c))
1087 break;
1088 }
1089 while (*p);
1090 }
1091
1092 p = file_name + prefix_len;
1093 while (ISSLASH (*p))
1094 p++;
1095
1096 return p;
1097 }
1098
1099
1100 const char *
_g_path_get_relative_basename_safe(const char * path,const char * base_dir,gboolean junk_paths)1101 _g_path_get_relative_basename_safe (const char *path,
1102 const char *base_dir,
1103 gboolean junk_paths)
1104 {
1105 return sanitize_filename (_g_path_get_relative_basename (path, base_dir, junk_paths));
1106 }
1107
1108
1109 gboolean
_g_filename_is_hidden(const gchar * name)1110 _g_filename_is_hidden (const gchar *name)
1111 {
1112 if (name[0] != '.') return FALSE;
1113 if (name[1] == '\0') return FALSE;
1114 if ((name[1] == '.') && (name[2] == '\0')) return FALSE;
1115
1116 return TRUE;
1117 }
1118
1119
1120 const char *
_g_filename_get_extension(const char * filename)1121 _g_filename_get_extension (const char *filename)
1122 {
1123 const char *ptr = filename;
1124 int len;
1125 int p;
1126 const char *ext;
1127
1128 if (filename == NULL)
1129 return NULL;
1130
1131 len = strlen (filename);
1132 if (len <= 1)
1133 return NULL;
1134
1135 p = len - 1;
1136 while ((p >= 0) && (ptr[p] != '.'))
1137 p--;
1138 if (p < 0)
1139 return NULL;
1140
1141 ext = filename + p;
1142 if (ext - 4 > filename) {
1143 const char *test = ext - 4;
1144 /* .tar.rz cannot be uncompressed in one step */
1145 if ((strncmp (test, ".tar", 4) == 0) && (strncmp (ext, ".rz", 2) != 0))
1146 ext = ext - 4;
1147 }
1148 return ext;
1149 }
1150
1151
1152 gboolean
_g_filename_has_extension(const char * filename,const char * ext)1153 _g_filename_has_extension (const char *filename,
1154 const char *ext)
1155 {
1156 int filename_l, ext_l;
1157
1158 filename_l = strlen (filename);
1159 ext_l = strlen (ext);
1160
1161 if (filename_l < ext_l)
1162 return FALSE;
1163 return strcasecmp (filename + filename_l - ext_l, ext) == 0;
1164 }
1165
1166
1167 char *
_g_filename_get_random(int random_part_len,const char * suffix)1168 _g_filename_get_random (int random_part_len,
1169 const char *suffix)
1170 {
1171 const char *letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
1172 const int n_letters = strlen (letters);
1173 int suffix_len;
1174 char *result, *c;
1175 GRand *rand;
1176 int i;
1177
1178 suffix_len = suffix != NULL ? strlen (suffix) + 1 : 0;
1179 result = g_new (char, suffix_len + random_part_len + 1);
1180
1181 rand = g_rand_new ();
1182 for (i = 0, c = result; i < random_part_len; i++, c++)
1183 *c = letters[g_rand_int_range (rand, 0, n_letters)];
1184 *c = '\0';
1185 g_rand_free (rand);
1186
1187 if (suffix != NULL) {
1188 strcpy (c, ".");
1189 strcpy (c + 1, suffix);
1190 }
1191
1192 return result;
1193 }
1194
1195
1196 gboolean
_g_mime_type_matches(const char * mime_type,const char * pattern)1197 _g_mime_type_matches (const char *mime_type,
1198 const char *pattern)
1199 {
1200 return (strcasecmp (mime_type, pattern) == 0);
1201 }
1202
1203
1204 const char *
_g_mime_type_get_from_content(char * buffer,gsize buffer_size)1205 _g_mime_type_get_from_content (char *buffer,
1206 gsize buffer_size)
1207 {
1208 static const struct magic {
1209 const unsigned int off;
1210 const unsigned int len;
1211 const char * const id;
1212 const char * const mime_type;
1213 }
1214 magic_ids [] = {
1215 /* magic ids taken from magic/Magdir/archive from the file-4.21 tarball */
1216 { 0, 6, "7z\274\257\047\034", "application/x-7z-compressed" },
1217 { 7, 7, "**ACE**", "application/x-ace" },
1218 { 0, 2, "\x60\xea", "application/x-arj" },
1219 { 0, 3, "BZh", "application/x-bzip2" },
1220 { 0, 2, "\037\213", "application/x-gzip" },
1221 { 0, 4, "LZIP", "application/x-lzip" },
1222 { 0, 9, "\x89\x4c\x5a\x4f\x00\x0d\x0a\x1a\x0a", "application/x-lzop", },
1223 { 0, 4, "Rar!", "application/x-rar" },
1224 { 0, 4, "RZIP", "application/x-rzip" },
1225 { 0, 6, "\3757zXZ\000", "application/x-xz" },
1226 { 20, 4, "\xdc\xa7\xc4\xfd", "application/x-zoo", },
1227 { 0, 4, "PK\003\004", "application/zip" },
1228 { 0, 8, "PK00PK\003\004", "application/zip" },
1229 { 0, 4, "LRZI", "application/x-lrzip" },
1230 { 0, 4, "\x28\xB5\x2F\xFD", "application/zstd" },
1231 };
1232
1233 int i;
1234
1235 for (i = 0; i < G_N_ELEMENTS (magic_ids); i++) {
1236 const struct magic * const magic = &magic_ids[i];
1237
1238 if ((magic->off + magic->len) > buffer_size)
1239 g_warning ("buffer underrun for mime-type '%s' magic", magic->mime_type);
1240 else if (! memcmp (buffer + magic->off, magic->id, magic->len))
1241 return magic->mime_type;
1242 }
1243
1244 return NULL;
1245 }
1246
1247
1248 /* GFile */
1249
1250
1251 int
_g_file_cmp_uris(GFile * a,GFile * b)1252 _g_file_cmp_uris (GFile *a,
1253 GFile *b)
1254 {
1255 char *uri_a;
1256 char *uri_b;
1257 int result;
1258
1259 uri_a = g_file_get_uri (a);
1260 uri_b = g_file_get_uri (b);
1261 result = g_strcmp0 (uri_a, uri_b);
1262
1263 g_free (uri_b);
1264 g_free (uri_a);
1265
1266 return result;
1267 }
1268
1269
1270 gboolean
_g_file_is_local(GFile * file)1271 _g_file_is_local (GFile *file)
1272 {
1273 char *scheme;
1274 gboolean is_local;
1275
1276 scheme = g_file_get_uri_scheme (file);
1277 is_local = strcmp (scheme, "file") == 0;
1278
1279 g_free (scheme);
1280
1281 return is_local;
1282 }
1283
1284
1285 GFile *
_g_file_get_home(void)1286 _g_file_get_home (void)
1287 {
1288 static GFile *file = NULL;
1289
1290 if (file != NULL)
1291 return file;
1292
1293 file = g_file_new_for_path (g_get_home_dir ());
1294
1295 return file;
1296 }
1297
1298
1299 char *
_g_file_get_display_basename(GFile * file)1300 _g_file_get_display_basename (GFile *file)
1301 {
1302 char *uri, *e_name, *name;
1303
1304 uri = g_file_get_uri (file);
1305 e_name = g_filename_display_basename (uri);
1306 name = g_uri_unescape_string (e_name, "");
1307
1308 g_free (e_name);
1309 g_free (uri);
1310
1311 return name;
1312 }
1313
1314
1315 GFile *
_g_file_new_home_relative(const char * partial_uri)1316 _g_file_new_home_relative (const char *partial_uri)
1317 {
1318 GFile *file;
1319 char *uri;
1320
1321 uri = g_strconcat (_g_uri_get_home (), "/", partial_uri, NULL);
1322 file = g_file_new_for_uri (uri);
1323 g_free (uri);
1324
1325 return file;
1326 }
1327
1328
1329 GList *
_g_file_list_dup(GList * l)1330 _g_file_list_dup (GList *l)
1331 {
1332 GList *r = NULL, *scan;
1333 for (scan = l; scan; scan = scan->next)
1334 r = g_list_prepend (r, g_file_dup ((GFile*) scan->data));
1335 return g_list_reverse (r);
1336 }
1337
1338
1339 void
_g_file_list_free(GList * l)1340 _g_file_list_free (GList *l)
1341 {
1342 GList *scan;
1343 for (scan = l; scan; scan = scan->next)
1344 g_object_unref (scan->data);
1345 g_list_free (l);
1346 }
1347
1348
1349 GList *
_g_file_list_new_from_uri_list(GList * uris)1350 _g_file_list_new_from_uri_list (GList *uris)
1351 {
1352 GList *r = NULL, *scan;
1353 for (scan = uris; scan; scan = scan->next)
1354 r = g_list_prepend (r, g_file_new_for_uri ((char*)scan->data));
1355 return g_list_reverse (r);
1356 }
1357
1358
1359 GFile *
_g_file_append_path(GFile * file,...)1360 _g_file_append_path (GFile *file,
1361 ...)
1362 {
1363 char *uri;
1364 const char *path;
1365 va_list args;
1366 GFile *new_file;
1367
1368 uri = g_file_get_uri (file);
1369
1370 va_start (args, file);
1371 while ((path = va_arg (args, const char *)) != NULL) {
1372 char *escaped;
1373 char *new_uri;
1374
1375 escaped = g_uri_escape_string (path, G_URI_RESERVED_CHARS_ALLOWED_IN_PATH, FALSE);
1376 new_uri = g_build_filename (uri, escaped, NULL);
1377 g_free (uri);
1378 uri = new_uri;
1379
1380 g_free (escaped);
1381 }
1382 va_end (args);
1383 new_file = g_file_new_for_uri (uri);
1384
1385 g_free (uri);
1386
1387 return new_file;
1388 }
1389
1390
1391 /* GKeyFile */
1392
1393
1394 GList *
_g_key_file_get_string_list(GKeyFile * key_file,const char * group_name,const char * key,GError ** error)1395 _g_key_file_get_string_list (GKeyFile *key_file,
1396 const char *group_name,
1397 const char *key,
1398 GError **error)
1399 {
1400 char **strv;
1401 GList *list;
1402 int i;
1403
1404 strv = g_key_file_get_string_list (key_file, group_name, key, NULL, error);
1405 if (strv == NULL)
1406 return NULL;
1407
1408 list = NULL;
1409 for (i = 0; strv[i] != NULL; i++)
1410 list = g_list_prepend (list, strv[i]);
1411
1412 g_free (strv);
1413
1414 return g_list_reverse (list);
1415 }
1416
1417
1418 /* GSettings utils */
1419
1420
1421 GSettings *
_g_settings_new_if_schema_installed(const char * schema_id)1422 _g_settings_new_if_schema_installed (const char *schema_id)
1423 {
1424 GSettingsSchema *schema;
1425
1426 schema = g_settings_schema_source_lookup (g_settings_schema_source_get_default (),
1427 schema_id,
1428 TRUE);
1429 if (schema == NULL)
1430 return NULL;
1431
1432 g_settings_schema_unref (schema);
1433
1434 return g_settings_new (schema_id);
1435 }
1436
1437
1438 /* line parser */
1439
1440
1441 gboolean
_g_line_matches_pattern(const char * line,const char * pattern)1442 _g_line_matches_pattern (const char *line,
1443 const char *pattern)
1444 {
1445 const char *l = line, *p = pattern;
1446
1447 for (/* void */; (*p != 0) && (*l != 0); p++, l++) {
1448 if (*p != '%') {
1449 if (*p != *l)
1450 return FALSE;
1451 }
1452 else {
1453 p++;
1454 switch (*p) {
1455 case 'a':
1456 break;
1457 case 'n':
1458 if (!isdigit (*l))
1459 return FALSE;
1460 break;
1461 case 'c':
1462 if (!isalpha (*l))
1463 return FALSE;
1464 break;
1465 default:
1466 return FALSE;
1467 }
1468 }
1469 }
1470
1471 return (*p == 0);
1472 }
1473
1474
1475 int
_g_line_get_index_from_pattern(const char * line,const char * pattern)1476 _g_line_get_index_from_pattern (const char *line,
1477 const char *pattern)
1478 {
1479 int line_l, pattern_l;
1480 const char *l;
1481
1482 line_l = strlen (line);
1483 pattern_l = strlen (pattern);
1484
1485 if ((pattern_l == 0) || (line_l == 0))
1486 return -1;
1487
1488 for (l = line; *l != 0; l++)
1489 if (_g_line_matches_pattern (l, pattern))
1490 return (l - line);
1491
1492 return -1;
1493 }
1494
1495
1496 char*
_g_line_get_next_field(const char * line,int start_from,int field_n)1497 _g_line_get_next_field (const char *line,
1498 int start_from,
1499 int field_n)
1500 {
1501 const char *f_start, *f_end;
1502
1503 line = line + start_from;
1504
1505 f_start = line;
1506 while ((*f_start == ' ') && (*f_start != *line))
1507 f_start++;
1508 f_end = f_start;
1509
1510 while ((field_n > 0) && (*f_end != 0)) {
1511 if (*f_end == ' ') {
1512 field_n--;
1513 if (field_n != 0) {
1514 while ((*f_end == ' ') && (*f_end != *line))
1515 f_end++;
1516 f_start = f_end;
1517 }
1518 }
1519 else
1520 f_end++;
1521 }
1522
1523 return g_strndup (f_start, f_end - f_start);
1524 }
1525
1526
1527 char*
_g_line_get_prev_field(const char * line,int start_from,int field_n)1528 _g_line_get_prev_field (const char *line,
1529 int start_from,
1530 int field_n)
1531 {
1532 const char *f_start, *f_end;
1533
1534 f_start = line + start_from - 1;
1535 while ((*f_start == ' ') && (*f_start != *line))
1536 f_start--;
1537 f_end = f_start;
1538
1539 while ((field_n > 0) && (*f_start != *line)) {
1540 if (*f_start == ' ') {
1541 field_n--;
1542 if (field_n != 0) {
1543 while ((*f_start == ' ') && (*f_start != *line))
1544 f_start--;
1545 f_end = f_start;
1546 }
1547 }
1548 else
1549 f_start--;
1550 }
1551
1552 return g_strndup (f_start + 1, f_end - f_start);
1553 }
1554
1555 /* threading */
1556
1557 gchar *
fr_get_thread_count(void)1558 fr_get_thread_count (void)
1559 {
1560 gchar *cpus;
1561 if (g_get_num_processors() >= 8)
1562 cpus = g_strdup_printf("%u", g_get_num_processors() - 2);
1563 else if (g_get_num_processors() >= 4)
1564 cpus = g_strdup_printf("%u", g_get_num_processors() - 1);
1565 else
1566 cpus = g_strdup_printf("%u", g_get_num_processors());
1567 return cpus;
1568 }
1569
1570 /* debug */
1571
1572 void
debug(const char * file,int line,const char * function,const char * format,...)1573 debug (const char *file,
1574 int line,
1575 const char *function,
1576 const char *format, ...)
1577 {
1578 #ifdef DEBUG
1579 va_list args;
1580 char *str;
1581
1582 g_return_if_fail (format != NULL);
1583
1584 va_start (args, format);
1585 str = g_strdup_vprintf (format, args);
1586 va_end (args);
1587
1588 g_fprintf (stderr, "[FR] %s:%d (%s):\n\t%s\n", file, line, function, str);
1589
1590 g_free (str);
1591 #else /* ! DEBUG */
1592 #endif
1593 }
1594