Branch data Line data Source code
1 : : /********************************************************************\
2 : : * gnc-glib-utils.c -- utility functions based on glib functions *
3 : : * Copyright (C) 2006 David Hampton <hampton@employees.org> *
4 : : * *
5 : : * This program is free software; you can redistribute it and/or *
6 : : * modify it under the terms of the GNU General Public License as *
7 : : * published by the Free Software Foundation; either version 2 of *
8 : : * the License, or (at your option) any later version. *
9 : : * *
10 : : * This program is distributed in the hope that it will be useful, *
11 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 : : * GNU General Public License for more details. *
14 : : * *
15 : : * You should have received a copy of the GNU General Public License*
16 : : * along with this program; if not, contact: *
17 : : * *
18 : : * Free Software Foundation Voice: +1-617-542-5942 *
19 : : * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
20 : : * Boston, MA 02110-1301, USA gnu@gnu.org *
21 : : * *
22 : : \********************************************************************/
23 : :
24 : : #include <config.h>
25 : : #include <errno.h>
26 : : #include <stdio.h>
27 : : #include <signal.h>
28 : : #include <string.h>
29 : :
30 : : #include "gnc-glib-utils.h"
31 : :
32 : : #ifdef G_OS_WIN32
33 : : #include <windows.h>
34 : : #endif
35 : :
36 : : int
37 : 90261 : safe_utf8_collate (const char * da, const char * db)
38 : : {
39 : 90261 : if (da && !(*da))
40 : 0 : da = NULL;
41 : 90261 : if (db && !(*db))
42 : 0 : db = NULL;
43 : :
44 : 90261 : if (da && db)
45 : 90261 : return g_utf8_collate(da, db);
46 : 0 : if (da)
47 : 0 : return 1;
48 : 0 : if (db)
49 : 0 : return -1;
50 : 0 : return 0;
51 : : }
52 : :
53 : : /********************************************************************
54 : : * The following definitions are from gutf8.c, for use by
55 : : * gnc_utf8_validate(). These are all verbatim copies, except for
56 : : * UNICODE_VALID() which has been modified to look for the strict
57 : : * subset of UTF-8 that is valid XML text.
58 : : */
59 : :
60 : : #define UTF8_COMPUTE(Char, Mask, Len) \
61 : : if (Char < 128) \
62 : : { \
63 : : Len = 1; \
64 : : Mask = 0x7f; \
65 : : } \
66 : : else if ((Char & 0xe0) == 0xc0) \
67 : : { \
68 : : Len = 2; \
69 : : Mask = 0x1f; \
70 : : } \
71 : : else if ((Char & 0xf0) == 0xe0) \
72 : : { \
73 : : Len = 3; \
74 : : Mask = 0x0f; \
75 : : } \
76 : : else if ((Char & 0xf8) == 0xf0) \
77 : : { \
78 : : Len = 4; \
79 : : Mask = 0x07; \
80 : : } \
81 : : else if ((Char & 0xfc) == 0xf8) \
82 : : { \
83 : : Len = 5; \
84 : : Mask = 0x03; \
85 : : } \
86 : : else if ((Char & 0xfe) == 0xfc) \
87 : : { \
88 : : Len = 6; \
89 : : Mask = 0x01; \
90 : : } \
91 : : else \
92 : : Len = -1;
93 : :
94 : : #define UTF8_LENGTH(Char) \
95 : : ((Char) < 0x80 ? 1 : \
96 : : ((Char) < 0x800 ? 2 : \
97 : : ((Char) < 0x10000 ? 3 : \
98 : : ((Char) < 0x200000 ? 4 : \
99 : : ((Char) < 0x4000000 ? 5 : 6)))))
100 : :
101 : :
102 : : #define UTF8_GET(Result, Chars, Count, Mask, Len) \
103 : : (Result) = (Chars)[0] & (Mask); \
104 : : for ((Count) = 1; (Count) < (Len); ++(Count)) \
105 : : { \
106 : : if (((Chars)[(Count)] & 0xc0) != 0x80) \
107 : : { \
108 : : (Result) = -1; \
109 : : break; \
110 : : } \
111 : : (Result) <<= 6; \
112 : : (Result) |= ((Chars)[(Count)] & 0x3f); \
113 : : }
114 : :
115 : : #define UNICODE_VALID(Char) \
116 : : ((Char) < 0x110000 && \
117 : : (((Char) & 0xFFFFF800) != 0xD800) && \
118 : : ((Char) < 0xFDD0 || (Char) > 0xFDEF) && \
119 : : ((Char) >= 0x20 || (Char) == 0x09 || (Char) == 0x0A || (Char) == 0x0D) && \
120 : : ((Char) & 0xFFFE) != 0xFFFE)
121 : :
122 : : gboolean
123 : 5 : gnc_utf8_validate(const gchar *str,
124 : : gssize max_len,
125 : : const gchar **end)
126 : : {
127 : :
128 : : const gchar *p;
129 : :
130 : 5 : g_return_val_if_fail (str != NULL, FALSE);
131 : :
132 : 5 : if (end)
133 : 5 : *end = str;
134 : :
135 : 5 : p = str;
136 : :
137 : 214 : while ((max_len < 0 || (p - str) < max_len) && *p)
138 : : {
139 : 212 : int i, mask = 0, len;
140 : : gunichar result;
141 : 212 : unsigned char c = (unsigned char) * p;
142 : :
143 : 212 : UTF8_COMPUTE (c, mask, len);
144 : :
145 : 212 : if (len == -1)
146 : 1 : break;
147 : :
148 : : /* check that the expected number of bytes exists in str */
149 : 211 : if (max_len >= 0 &&
150 : 0 : ((max_len - (p - str)) < len))
151 : 0 : break;
152 : :
153 : 382 : UTF8_GET (result, p, i, mask, len);
154 : :
155 : 211 : if (UTF8_LENGTH (result) != len) /* Check for overlong UTF-8 */
156 : 1 : break;
157 : :
158 : 210 : if (result == (gunichar) - 1)
159 : 0 : break;
160 : :
161 : 210 : if (!UNICODE_VALID (result))
162 : : break;
163 : :
164 : 209 : p += len;
165 : : }
166 : :
167 : 5 : if (end)
168 : 5 : *end = p;
169 : :
170 : : /* See that we covered the entire length if a length was
171 : : * passed in, or that we ended on a nul if not
172 : : */
173 : 5 : if (max_len >= 0 &&
174 : 0 : p != (str + max_len))
175 : 0 : return FALSE;
176 : 5 : else if (max_len < 0 &&
177 : 5 : *p != '\0')
178 : 3 : return FALSE;
179 : : else
180 : 2 : return TRUE;
181 : : }
182 : :
183 : : void
184 : 2 : gnc_utf8_strip_invalid (gchar *str)
185 : : {
186 : : gchar *end;
187 : : gint len;
188 : :
189 : 2 : g_return_if_fail(str);
190 : :
191 : 2 : if (gnc_utf8_validate(str, -1, (const gchar **)&end))
192 : 0 : return;
193 : :
194 : 2 : g_warning("Invalid utf8 string: %s", str);
195 : : do
196 : : {
197 : 3 : len = strlen(end);
198 : 3 : memmove(end, end + 1, len); /* shuffle the remainder one byte */
199 : : }
200 : 3 : while (!gnc_utf8_validate(str, -1, (const gchar **)&end));
201 : : }
202 : :
203 : : gchar *
204 : 0 : gnc_utf8_strip_invalid_strdup(const gchar* str)
205 : : {
206 : 0 : gchar *result = g_strdup (str);
207 : 0 : gnc_utf8_strip_invalid (result);
208 : 0 : return result;
209 : : }
210 : :
211 : : void
212 : 2 : gnc_utf8_strip_invalid_and_controls (gchar *str)
213 : : {
214 : 2 : gchar *c = NULL;
215 : 2 : const gchar *controls = "\b\f\n\r\t\v";
216 : 2 : g_return_if_fail (str != NULL && strlen (str) > 0);
217 : 2 : gnc_utf8_strip_invalid (str); /* First fix the UTF-8 */
218 : 189 : for(c = str + strlen (str) - 1; c != str; --c)
219 : : {
220 : 187 : gboolean line_control = ((unsigned char)(*c) < 0x20);
221 : 187 : if (line_control || strchr(controls, *c) != NULL)
222 : 2 : *c = ' '; /*replace controls with a single space. */
223 : : }
224 : : }
225 : :
226 : : gchar *
227 : 0 : gnc_locale_from_utf8(const gchar* str)
228 : : {
229 : : gchar * locale_str;
230 : 0 : gsize bytes_written = 0;
231 : 0 : GError * err = NULL;
232 : :
233 : : /* Convert from UTF-8 to the encoding used in the current locale. */
234 : 0 : locale_str = g_locale_from_utf8(str, -1, NULL, &bytes_written, &err);
235 : 0 : if (err)
236 : : {
237 : 0 : g_warning("g_locale_from_utf8 failed: %s", err->message);
238 : 0 : g_error_free(err);
239 : : }
240 : :
241 : 0 : return locale_str;
242 : : }
243 : :
244 : : gchar *
245 : 0 : gnc_locale_to_utf8(const gchar* str)
246 : : {
247 : : gchar * utf8_str;
248 : 0 : gsize bytes_written = 0;
249 : 0 : GError * err = NULL;
250 : :
251 : : /* Convert to UTF-8 from the encoding used in the current locale. */
252 : 0 : utf8_str = g_locale_to_utf8(str, -1, NULL, &bytes_written, &err);
253 : 0 : if (err)
254 : : {
255 : 0 : g_warning("g_locale_to_utf8 failed: %s", err->message);
256 : 0 : g_error_free(err);
257 : : }
258 : :
259 : 0 : return utf8_str;
260 : : }
261 : :
262 : : GList*
263 : 17 : gnc_g_list_map(GList* list, GncGMapFunc fn, gpointer user_data)
264 : : {
265 : 17 : GList *rtn = NULL;
266 : 33 : for (; list != NULL; list = list->next)
267 : : {
268 : 16 : rtn = g_list_prepend (rtn, (*fn)(list->data, user_data));
269 : : }
270 : 17 : return g_list_reverse (rtn);
271 : : }
272 : :
273 : : void
274 : 0 : gnc_g_list_cut(GList **list, GList *cut_point)
275 : : {
276 : 0 : if (list == NULL || *list == NULL)
277 : 0 : return;
278 : :
279 : : // if it's the first element.
280 : 0 : if (cut_point->prev == NULL)
281 : : {
282 : 0 : *list = NULL;
283 : 0 : return;
284 : : }
285 : :
286 : 0 : cut_point->prev->next = NULL;
287 : 0 : cut_point->prev = NULL;
288 : : }
289 : :
290 : :
291 : : gchar *
292 : 13 : gnc_g_list_stringjoin (GList *list_of_strings, const gchar *sep)
293 : : {
294 : 13 : gint seplen = sep ? strlen(sep) : 0;
295 : 13 : gint length = -seplen;
296 : : gchar *retval, *p;
297 : :
298 : 43 : for (GList *n = list_of_strings; n; n = n->next)
299 : : {
300 : 30 : gchar *str = n->data;
301 : 30 : if (str && *str)
302 : 24 : length += strlen (str) + seplen;
303 : : }
304 : :
305 : 13 : if (length <= 0)
306 : 2 : return NULL;
307 : :
308 : 11 : p = retval = (gchar*) g_malloc0 (length * sizeof (gchar) + 1);
309 : 41 : for (GList *n = list_of_strings; n; n = n->next)
310 : : {
311 : 30 : gchar *str = n->data;
312 : 30 : if (!str || !str[0])
313 : 6 : continue;
314 : 24 : if (sep && (p != retval))
315 : 10 : p = g_stpcpy (p, sep);
316 : 24 : p = g_stpcpy (p, str);
317 : : }
318 : :
319 : 11 : return retval;
320 : : }
321 : :
322 : : gint
323 : 8 : gnc_list_length_cmp (const GList *list, size_t len)
324 : : {
325 : 15 : for (GList *lst = (GList*) list;; lst = g_list_next (lst), len--)
326 : : {
327 : 15 : if (!lst) return (len ? -1 : 0);
328 : 9 : if (!len) return 1;
329 : : }
330 : : }
|