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