1 /*
2  * panel-glib.c: various small extensions to glib
3  *
4  * Copyright (C) 2008 Novell, Inc.
5  * Copyright (C) 2012-2021 MATE Developers
6  *
7  * Originally based on code from panel-util.c (there was no relevant copyright
8  * header at the time), but the code was:
9  * Copyright (C) Novell, Inc. (for the panel_g_utf8_strstrcase() code)
10  * Copyright (C) Dennis Cranston (for the panel_g_lookup_in_data_dirs() code)
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License as
14  * published by the Free Software Foundation; either version 2 of the
15  * License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful, but
18  * WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  * General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
25  * 02110-1301, USA.
26  *
27  * Authors:
28  *	Vincent Untz <vuntz@gnome.org>
29  */
30 
31 #include <string.h>
32 
33 #include <glib.h>
34 
35 #include "panel-glib.h"
36 
37 typedef char * (*LookupInDir) (const char *basename, const char *dir);
38 
39 static char *
_lookup_in_dir(const char * basename,const char * dir)40 _lookup_in_dir (const char *basename,
41 		const char *dir)
42 {
43 	char *path;
44 
45 	path = g_build_filename (dir, basename, NULL);
46 	if (!g_file_test (path, G_FILE_TEST_EXISTS)) {
47 		g_free (path);
48 		return NULL;
49 	}
50 
51 	return path;
52 }
53 
54 static char *
_lookup_in_applications_subdir(const char * basename,const char * dir)55 _lookup_in_applications_subdir (const char *basename,
56 				const char *dir)
57 {
58 	char *path;
59 
60 	path = g_build_filename (dir, "applications", basename, NULL);
61 	if (!g_file_test (path, G_FILE_TEST_EXISTS)) {
62 		g_free (path);
63 		return NULL;
64 	}
65 
66 	return path;
67 }
68 
69 static char *
_panel_g_lookup_in_data_dirs_internal(const char * basename,LookupInDir lookup)70 _panel_g_lookup_in_data_dirs_internal (const char *basename,
71 				       LookupInDir lookup)
72 {
73 	const char * const *system_data_dirs;
74 	const char          *user_data_dir;
75 	char                *retval;
76 	int                  i;
77 
78 	user_data_dir    = g_get_user_data_dir ();
79 	system_data_dirs = g_get_system_data_dirs ();
80 
81 	if ((retval = lookup (basename, user_data_dir)))
82 		return retval;
83 
84 	for (i = 0; system_data_dirs[i]; i++)
85 		if ((retval = lookup (basename, system_data_dirs[i])))
86 			return retval;
87 
88 	return NULL;
89 }
90 
91 char *
panel_g_lookup_in_data_dirs(const char * basename)92 panel_g_lookup_in_data_dirs (const char *basename)
93 {
94 	return _panel_g_lookup_in_data_dirs_internal (basename,
95 						      _lookup_in_dir);
96 }
97 
98 char *
panel_g_lookup_in_applications_dirs(const char * basename)99 panel_g_lookup_in_applications_dirs (const char *basename)
100 {
101 	return _panel_g_lookup_in_data_dirs_internal (basename,
102 						      _lookup_in_applications_subdir);
103 }
104 
105 /* Copied from evolution-data-server/libedataserver/e-util.c:
106  * e_util_unicode_get_utf8() */
107 static char *
_unicode_get_utf8(const char * text,gunichar * out)108 _unicode_get_utf8 (const char *text, gunichar *out)
109 {
110 	*out = g_utf8_get_char (text);
111 	return (*out == (gunichar)-1) ? NULL : g_utf8_next_char (text);
112 }
113 
114 /* Copied from evolution-data-server/libedataserver/e-util.c:
115  * e_util_utf8_strstrcase() */
116 const char *
panel_g_utf8_strstrcase(const char * haystack,const char * needle)117 panel_g_utf8_strstrcase (const char *haystack, const char *needle)
118 {
119 	gunichar *nuni;
120 	gunichar unival;
121 	gint nlen;
122 	const char *o, *p;
123 
124 	if (haystack == NULL) return NULL;
125 	if (needle == NULL) return NULL;
126 	if (strlen (needle) == 0) return haystack;
127 	if (strlen (haystack) == 0) return NULL;
128 
129 	nuni = g_alloca (sizeof (gunichar) * strlen (needle));
130 
131 	nlen = 0;
132 	for (p = _unicode_get_utf8 (needle, &unival);
133 	     p && unival;
134 	     p = _unicode_get_utf8 (p, &unival)) {
135 		nuni[nlen++] = g_unichar_tolower (unival);
136 	}
137 	/* NULL means there was illegal utf-8 sequence */
138 	if (!p) return NULL;
139 
140 	o = haystack;
141 	for (p = _unicode_get_utf8 (o, &unival);
142 	     p && unival;
143 	     p = _unicode_get_utf8 (p, &unival)) {
144 		gint sc;
145 		sc = g_unichar_tolower (unival);
146 		/* We have valid stripped char */
147 		if (sc == nuni[0]) {
148 			const char *q = p;
149 			gint npos = 1;
150 			while (npos < nlen) {
151 				q = _unicode_get_utf8 (q, &unival);
152 				if (!q || !unival) return NULL;
153 				sc = g_unichar_tolower (unival);
154 				if (sc != nuni[npos]) break;
155 				npos++;
156 			}
157 			if (npos == nlen) {
158 				return o;
159 			}
160 		}
161 		o = p;
162 	}
163 
164 	return NULL;
165 }
166