1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Copyright (C) 2003 Novell Inc.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of version 2 of the GNU Lesser General Public
7 * License as published by the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
19 * Authors: Rodrigo Moya <rodrigo@ximian.com>
31 #include "e-data-server-util.h"
35 * @path: The directory hierarchy to create.
36 * @mode: The permissions to use for the directories.
38 * Creates a directory hierarchy based on the string @path. If @path
39 * is an absolute path, the directories will be created relative to
40 * the root of the file system; otherwise, the directories will be
41 * created relative to the current directory.
43 * Returns: 0 on success; -1 on failure.
46 e_util_mkdir_hier (const char *path, mode_t mode)
48 return g_mkdir_with_parents (path, mode);
53 * @haystack: The string to search in.
54 * @needle: The string to search for.
56 * Find the first instance of @needle in @haystack, ignoring case for
57 * bytes that are ASCII characters.
59 * Returns: A pointer to the start of @needle in @haystack, or NULL if
60 * @needle is not found.
63 e_util_strstrcase (const gchar *haystack, const gchar *needle)
65 /* find the needle in the haystack neglecting case */
69 g_return_val_if_fail (haystack != NULL, NULL);
70 g_return_val_if_fail (needle != NULL, NULL);
73 if (len > strlen(haystack))
77 return (gchar *) haystack;
79 for (ptr = haystack; *(ptr + len - 1) != '\0'; ptr++)
80 if (!g_ascii_strncasecmp (ptr, needle, len))
87 * e_util_unicode_get_utf8:
88 * @text: The string to take the UTF-8 character from.
89 * @out: The location to store the UTF-8 character in.
91 * Get a UTF-8 character from the beginning of @text.
93 * Returns: A pointer to the next character in @text after @out.
96 e_util_unicode_get_utf8 (const gchar *text, gunichar *out)
98 *out = g_utf8_get_char (text);
99 return (*out == (gunichar)-1) ? NULL : g_utf8_next_char (text);
103 * e_util_utf8_strstrcase:
104 * @haystack: The string to search in.
105 * @needle: The string to search for.
107 * Find the first instance of @needle in @haystack, ignoring case. (No
108 * proper case folding or decomposing is done.) Both @needle and
109 * @haystack are UTF-8 strings.
111 * Returns: A pointer to the first instance of @needle in @haystack, or
112 * %NULL if no match is found, or if either of the strings are
113 * not legal UTF-8 strings.
116 e_util_utf8_strstrcase (const gchar *haystack, const gchar *needle)
123 if (haystack == NULL) return NULL;
124 if (needle == NULL) return NULL;
125 if (strlen (needle) == 0) return haystack;
126 if (strlen (haystack) == 0) return NULL;
128 nuni = g_alloca (sizeof (gunichar) * strlen (needle));
131 for (p = e_util_unicode_get_utf8 (needle, &unival); p && unival; p = e_util_unicode_get_utf8 (p, &unival)) {
132 nuni[nlen++] = g_unichar_tolower (unival);
134 /* NULL means there was illegal utf-8 sequence */
138 for (p = e_util_unicode_get_utf8 (o, &unival); p && unival; p = e_util_unicode_get_utf8 (p, &unival)) {
140 sc = g_unichar_tolower (unival);
141 /* We have valid stripped char */
145 while (npos < nlen) {
146 q = e_util_unicode_get_utf8 (q, &unival);
147 if (!q || !unival) return NULL;
148 sc = g_unichar_tolower (unival);
149 if (sc != nuni[npos]) break;
164 stripped_char (gunichar ch)
166 gunichar *decomp, retval;
170 utype = g_unichar_type (ch);
173 case G_UNICODE_CONTROL:
174 case G_UNICODE_FORMAT:
175 case G_UNICODE_UNASSIGNED:
176 case G_UNICODE_COMBINING_MARK:
181 /* Convert to lowercase, fall through */
182 ch = g_unichar_tolower (ch);
183 case G_UNICODE_LOWERCASE_LETTER:
184 if ((decomp = g_unicode_canonical_decomposition (ch, &dlen))) {
196 * e_util_utf8_strstrcasedecomp:
197 * @haystack: The string to search in.
198 * @needle: The string to search for.
200 * Find the first instance of @needle in @haystack, where both @needle
201 * and @haystack are UTF-8 strings. Both strings are stripped and
202 * decomposed for comparison, and case is ignored.
204 * Returns: A pointer to the first instance of @needle in @haystack, or
205 * %NULL if either of the strings are not legal UTF-8 strings.
208 e_util_utf8_strstrcasedecomp (const gchar *haystack, const gchar *needle)
215 if (haystack == NULL) return NULL;
216 if (needle == NULL) return NULL;
217 if (strlen (needle) == 0) return haystack;
218 if (strlen (haystack) == 0) return NULL;
220 nuni = g_alloca (sizeof (gunichar) * strlen (needle));
223 for (p = e_util_unicode_get_utf8 (needle, &unival); p && unival; p = e_util_unicode_get_utf8 (p, &unival)) {
225 sc = stripped_char (unival);
230 /* NULL means there was illegal utf-8 sequence */
232 /* If everything is correct, we have decomposed, lowercase, stripped needle */
233 if (nlen < 1) return haystack;
236 for (p = e_util_unicode_get_utf8 (o, &unival); p && unival; p = e_util_unicode_get_utf8 (p, &unival)) {
238 sc = stripped_char (unival);
240 /* We have valid stripped char */
244 while (npos < nlen) {
245 q = e_util_unicode_get_utf8 (q, &unival);
246 if (!q || !unival) return NULL;
247 sc = stripped_char (unival);
248 if ((!sc) || (sc != nuni[npos])) break;
263 e_util_utf8_strcasecmp (const gchar *s1, const gchar *s2)
265 gchar *folded_s1, *folded_s2;
268 g_return_val_if_fail (s1 != NULL && s2 != NULL, -1);
270 if (strcmp (s1, s2) == 0)
273 folded_s1 = g_utf8_casefold (s1, -1);
274 folded_s2 = g_utf8_casefold (s2, -1);
276 retval = g_utf8_collate (folded_s1, folded_s2);
286 * @s: The string array to store the result in.
287 * @max: The size of array @s.
288 * @fmt: The formatting to use on @tm.
289 * @tm: The time value to format.
291 * This function is a wrapper around the strftime(3) function, which
292 * converts the %l and %k (12h and 24h) format variables if necessary.
294 * Returns: The number of characters placed in @s.
296 size_t e_strftime(char *s, size_t max, const char *fmt, const struct tm *tm)
299 #ifdef HAVE_LKSTRFTIME
300 ret = strftime(s, max, fmt, tm);
304 ffmt = g_strdup(fmt);
306 while ((c = strstr(ff, "%l")) != NULL) {
312 while ((c = strstr(ff, "%k")) != NULL) {
318 /* The Microsoft strftime() doesn't have %e either */
320 while ((c = strstr(ff, "%e")) != NULL) {
326 ret = strftime(s, max, ffmt, tm);
329 if (ret == 0 && max > 0)
336 * @s: The string array to store the result in.
337 * @max: The size of array @s.
338 * @fmt: The formatting to use on @tm.
339 * @tm: The time value to format.
341 * The UTF-8 equivalent of e_strftime().
343 * Returns: The number of characters placed in @s.
346 e_utf8_strftime(char *s, size_t max, const char *fmt, const struct tm *tm)
349 char *locale_fmt, *buf;
351 locale_fmt = g_locale_from_utf8(fmt, -1, NULL, &sz, NULL);
355 ret = e_strftime(s, max, locale_fmt, tm);
361 buf = g_locale_to_utf8(s, ret, NULL, &sz, NULL);
368 char *tmp = buf + max - 1;
369 tmp = g_utf8_find_prev_char(buf, tmp);
384 * @t: A pthread_t value
386 * Returns a 64-bit integer hopefully uniquely identifying the
387 * thread. To be used in debugging output and logging only. To test
388 * whether two pthread_t values refer to the same thread, use
391 * There is no guarantee that calling e_util_pthread_id() on one
392 * thread first and later after that thread has dies on another won't
393 * return the same integer.
395 * On some platforms it might even be that when called two times on
396 * the same thread's pthread_t (with some pthread API calls inbetween)
397 * we will return different values (this of course makes this function
398 * rather useless on such platforms).
400 * On Linux and Win32, known to really return a unique id for each
401 * thread existing at a certain time. No guarantee that ids won't be
402 * reused after a thread has terminated, though.
404 * Returns: A 64-bit integer.
407 e_util_pthread_id (pthread_t t)
409 #ifdef HAVE_GUINT64_CASTABLE_PTHREAD_T
410 /* We know that pthread_t is an integral type, or at least
411 * castable to such without loss of precision.
414 #elif defined (PTW32_VERSION)
415 /* pthreads-win32 implementation on Windows: Return the
416 * pointer to the "actual object" (see pthread.h)
418 #if GLIB_SIZEOF_VOID_P == 8
420 return (guint64) t.p;
425 /* Just return a checksum of the contents of the pthread_t */
428 guchar *const tend = (guchar *) ((&t)+1);
429 guchar *tp = (guchar *) &t;
432 retval = (retval << 5) - retval * *tp++;
439 /* This only makes a filename safe for usage as a filename. It still may have shell meta-characters in it. */
441 /* This code is rather misguided and mostly pointless, but can't be
442 * changed because of backward compatibility, I guess.
444 * It replaces some perfectly safe characters like '%' with an
445 * underscore. (Recall that on Unix, the only bytes not allowed in a
446 * file name component are '\0' and '/'.) On the other hand, the UTF-8
447 * for a printable non-ASCII Unicode character (that thus consists of
448 * several very nonprintable non-ASCII bytes) is let through as
449 * such. But those bytes are of course also allowed in filenames, so
450 * it doesn't matter as such...
453 e_filename_make_safe (gchar *string)
458 const char *unsafe_chars = " /'\"`&();|<>$%{}!\\:*?#";
460 const char *unsafe_chars = " /'\"`&();|<>$%{}!#";
463 g_return_if_fail (string != NULL);
467 c = g_utf8_get_char (p);
469 p = g_utf8_next_char (p);
470 /* I wonder what this code is supposed to actually
471 * achieve, and whether it does that as currently
474 if (!g_unichar_isprint(c) || ( c < 0xff && strchr (unsafe_chars, c&0xff ))) {
485 /* The following function is lifted from libgnome. We don't want
486 * libedataserver to depend on libgnome, especially as libgnome is
487 * being deprecated. This function will move to GLib, presumably, but
492 * gnome_win32_get_prefixes:
493 * @hmodule: The handle to a DLL (a HMODULE).
494 * @full_prefix: Where the full UTF-8 path to the DLL's installation folder
496 * @cp_prefix: Where a system codepage version of
497 * the installation folder will be returned.
499 * This function looks up the installation prefix of the DLL (or EXE)
500 * with handle @hmodule. The prefix using long filenames and in UTF-8
501 * form is returned in @full_prefix. The prefix using short file names
502 * (if present in the file system) and in the system codepage is
503 * returned in @cp_prefix. To determine the installation prefix, the
504 * full path to the DLL or EXE is first fetched. If the last folder
505 * component in that path is called "bin", its parent folder is used,
506 * otherwise the folder itself.
508 * If either can't be obtained, %NULL is stored. The caller should be
509 * prepared to handle that.
511 * The returned character pointers are newly allocated and should be
512 * freed with g_free when not longer needed.
515 get_prefixes (gpointer hmodule,
522 g_return_if_fail (full_prefix != NULL);
523 g_return_if_fail (cp_prefix != NULL);
528 if (G_WIN32_HAVE_WIDECHAR_API ()) {
529 /* NT-based Windows has wide char API */
530 if (GetModuleFileNameW ((HMODULE) hmodule, wcbfr, G_N_ELEMENTS (wcbfr))) {
531 *full_prefix = g_utf16_to_utf8 (wcbfr, -1,
533 if (GetShortPathNameW (wcbfr, wcbfr, G_N_ELEMENTS (wcbfr)) &&
534 /* Short pathnames always contain only
535 * ASCII, I think, but just in case, be
538 WideCharToMultiByte (CP_ACP, 0, wcbfr, -1,
539 cpbfr, G_N_ELEMENTS (cpbfr),
541 *cp_prefix = g_strdup (cpbfr);
542 else if (*full_prefix)
543 *cp_prefix = g_locale_from_utf8 (*full_prefix, -1,
548 if (GetModuleFileNameA ((HMODULE) hmodule, cpbfr, G_N_ELEMENTS (cpbfr))) {
549 *full_prefix = g_locale_to_utf8 (cpbfr, -1,
551 *cp_prefix = g_strdup (cpbfr);
555 if (*full_prefix != NULL) {
556 gchar *p = strrchr (*full_prefix, '\\');
560 p = strrchr (*full_prefix, '\\');
561 if (p && (g_ascii_strcasecmp (p + 1, "bin") == 0))
565 /* cp_prefix is in system codepage */
566 if (*cp_prefix != NULL) {
567 gchar *p = _mbsrchr (*cp_prefix, '\\');
571 p = _mbsrchr (*cp_prefix, '\\');
572 if (p && (g_ascii_strcasecmp (p + 1, "bin") == 0))
577 static const char *prefix = NULL;
578 static const char *cp_prefix;
580 static const char *localedir;
581 static const char *extensiondir;
582 static const char *imagesdir;
583 static const char *ui_gladedir;
585 static HMODULE hmodule;
586 G_LOCK_DEFINE_STATIC (mutex);
588 /* Silence gcc with a prototype. Yes, this is silly. */
589 BOOL WINAPI DllMain (HINSTANCE hinstDLL,
593 /* Minimal DllMain that just tucks away the DLL's HMODULE */
595 DllMain (HINSTANCE hinstDLL,
600 case DLL_PROCESS_ATTACH:
608 e_util_replace_prefix (const char *configure_time_prefix,
609 const char *runtime_prefix,
610 const char *configure_time_path)
612 char *c_t_prefix_slash = g_strconcat (configure_time_prefix, "/",
616 if (runtime_prefix &&
617 g_str_has_prefix (configure_time_path, c_t_prefix_slash)) {
618 retval = g_strconcat (runtime_prefix,
619 configure_time_path + strlen (configure_time_prefix),
622 retval = g_strdup (configure_time_path);
624 g_free (c_t_prefix_slash);
630 replace_prefix (const char *runtime_prefix,
631 const char *configure_time_path)
633 return e_util_replace_prefix (E_DATA_SERVER_PREFIX,
635 configure_time_path);
645 if (prefix != NULL) {
650 /* This requires that the libedataserver DLL is installed in $bindir */
651 get_prefixes (hmodule, &full_pfx, &cp_pfx);
653 prefix = g_strdup (full_pfx);
654 cp_prefix = g_strdup (cp_pfx);
659 localedir = replace_prefix (cp_prefix, EVOLUTION_LOCALEDIR);
660 extensiondir = replace_prefix (prefix, E_DATA_SERVER_EXTENSIONDIR);
661 imagesdir = replace_prefix (prefix, E_DATA_SERVER_IMAGESDIR);
662 ui_gladedir = replace_prefix (prefix, E_DATA_SERVER_UI_GLADEDIR);
667 #include "libedataserver-private.h" /* For prototypes */
669 #define GETTER_IMPL(varbl) \
675 #define PRIVATE_GETTER(varbl) \
677 _libedataserver_get_##varbl (void) \
680 #define PUBLIC_GETTER(varbl) \
682 e_util_get_##varbl (void) \
685 PRIVATE_GETTER(extensiondir)
686 PRIVATE_GETTER(imagesdir)
687 PRIVATE_GETTER(ui_gladedir)
689 PUBLIC_GETTER(prefix)
690 PUBLIC_GETTER(cp_prefix)
691 PUBLIC_GETTER(localedir)
693 #endif /* G_OS_WIN32 */