EFL 1.7 svn doobies
[profile/ivi/eina.git] / src / lib / eina_prefix.c
1 /* EINA - EFL data type library
2  * Copyright (C) 2011 Carsten Haitzler
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library 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  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library;
16  * if not, see <http://www.gnu.org/licenses/>.
17  */
18
19 #ifdef HAVE_CONFIG_H
20 # include "config.h"
21 #endif
22
23 #ifdef STDC_HEADERS
24 # include <stdlib.h>
25 # include <stddef.h>
26 #else
27 # ifdef HAVE_STDLIB_H
28 #  include <stdlib.h>
29 # endif
30 #endif
31 #ifdef HAVE_ALLOCA_H
32 # include <alloca.h>
33 #elif !defined alloca
34 # ifdef __GNUC__
35 #  define alloca __builtin_alloca
36 # elif defined _AIX
37 #  define alloca __alloca
38 # elif defined _MSC_VER
39 #  include <malloc.h>
40 #  define alloca _alloca
41 # elif !defined HAVE_ALLOCA
42 #  ifdef  __cplusplus
43 extern "C"
44 #  endif
45 void *alloca (size_t);
46 # endif
47 #endif
48
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <sys/types.h>
53 #include <sys/stat.h>
54 #include <limits.h>
55
56 #ifdef HAVE_UNISTD_H
57 # include <unistd.h>
58 #endif
59
60 #ifdef HAVE_DLADDR
61 # include <dlfcn.h>
62 #endif
63
64 #ifdef HAVE_EVIL
65 # include <Evil.h>
66 #endif
67
68 #ifdef HAVE_ESCAPE
69 # include <Escape.h>
70 #endif
71
72 #include "eina_config.h"
73 #include "eina_private.h"
74 #include "eina_log.h"
75 #include "eina_prefix.h"
76
77 #ifdef _WIN32
78 # define PSEP_C ';'
79 # define DSEP_C '\\'
80 # define DSEP_S "\\"
81 #else
82 # define PSEP_C ':'
83 # define DSEP_C '/'
84 # define DSEP_S "/"
85 #endif /* _WIN32 */
86
87 /*============================================================================*
88  *                                  Local                                     *
89  *============================================================================*/
90
91 /**
92  * @cond LOCAL
93  */
94
95 struct _Eina_Prefix
96 {
97    char *exe_path;
98
99    char *prefix_path;
100    char *prefix_path_bin;
101    char *prefix_path_data;
102    char *prefix_path_lib;
103    char *prefix_path_locale;
104
105    unsigned char fallback : 1;
106    unsigned char no_common_prefix : 1;
107    unsigned char env_used : 1;
108 };
109
110 #define STRDUP_REP(x, y) do { if (x) free(x); x = strdup(y); } while (0)
111 #define IF_FREE_NULL(p) do { if (p) { free(p); p = NULL; } } while (0)
112
113 #ifndef EINA_LOG_COLOR_DEFAULT
114 #define EINA_LOG_COLOR_DEFAULT EINA_COLOR_CYAN
115 #endif
116
117 #ifdef ERR
118 #undef ERR
119 #endif
120 #define ERR(...) EINA_LOG_DOM_ERR(_eina_prefix_log_dom, __VA_ARGS__)
121
122 #ifdef WRN
123 #undef WRN
124 #endif
125 #define WRN(...) EINA_LOG_DOM_WARN(_eina_prefix_log_dom, __VA_ARGS__)
126
127 #ifdef INF
128 #undef INF
129 #endif
130 #define INF(...) EINA_LOG_DOM_INFO(_eina_prefix_log_dom, __VA_ARGS__)
131
132 #ifdef DBG
133 #undef DBG
134 #endif
135 #define DBG(...) EINA_LOG_DOM_DBG(_eina_prefix_log_dom, __VA_ARGS__)
136
137 static int _eina_prefix_log_dom = -1;
138
139 static int
140 _fallback(Eina_Prefix *pfx, const char *pkg_bin, const char *pkg_lib,
141           const char *pkg_data, const char *pkg_locale, const char *envprefix)
142 {
143    char *p;
144
145    STRDUP_REP(pfx->prefix_path, pkg_bin);
146    if (!pfx->prefix_path) return 0;
147    p = strrchr(pfx->prefix_path, DSEP_C);
148    if (p) *p = 0;
149    STRDUP_REP(pfx->prefix_path_bin, pkg_bin);
150    STRDUP_REP(pfx->prefix_path_lib, pkg_lib);
151    STRDUP_REP(pfx->prefix_path_data, pkg_data);
152    STRDUP_REP(pfx->prefix_path_locale, pkg_locale);
153    WRN("Could not determine its installed prefix for '%s'\n"
154        "      so am falling back on the compiled in default:\n"
155        "        %s\n"
156        "      implied by the following:\n"
157        "        bindir    = %s\n"
158        "        libdir    = %s\n"
159        "        datadir   = %s\n"
160        "        localedir = %s\n"
161        "      Try setting the following environment variables:\n"
162        "        %s_PREFIX     - points to the base prefix of install\n"
163        "      or the next 4 variables\n"
164        "        %s_BIN_DIR    - provide a specific binary directory\n"
165        "        %s_LIB_DIR    - provide a specific library directory\n"
166        "        %s_DATA_DIR   - provide a specific data directory\n"
167        "        %s_LOCALE_DIR - provide a specific locale directory",
168        envprefix,
169        pfx->prefix_path, pkg_bin, pkg_lib, pkg_data, pkg_locale,
170        envprefix, envprefix, envprefix, envprefix, envprefix);
171    pfx->fallback = 1;
172    return 1;
173 }
174
175 #ifndef _WIN32
176 static int
177 _try_proc(Eina_Prefix *pfx, void *symbol)
178 {
179    FILE *f;
180    char buf[4096];
181
182    DBG("Try /proc/self/maps");
183    f = fopen("/proc/self/maps", "rb");
184    if (!f) return 0;
185    DBG("Exists /proc/self/maps");
186    while (fgets(buf, sizeof(buf), f))
187      {
188         int len;
189         char *p, mode[5] = "";
190         unsigned long ptr1 = 0, ptr2 = 0;
191
192         len = strlen(buf);
193         if (buf[len - 1] == '\n')
194           {
195              buf[len - 1] = 0;
196              len--;
197           }
198         if (sscanf(buf, "%lx-%lx %4s", &ptr1, &ptr2, mode) == 3)
199           {
200              if (!strcmp(mode, "r-xp"))
201                {
202                   if (((void *)ptr1 <= symbol) && (symbol < (void *)ptr2))
203                     {
204                        DBG("Found in /proc/self/maps: %s", buf);
205                        p = strchr(buf, '/');
206                        if (p)
207                          {
208                             DBG("Found in /proc/self/maps: found last /");
209                             if (len > 10)
210                               {
211                                  if (!strcmp(buf + len - 10, " (deleted)"))
212                                     buf[len - 10] = 0;
213                               }
214                             STRDUP_REP(pfx->exe_path, p);
215                             INF("Found in /proc/self/maps: guess exe path is %s", pfx->exe_path);
216                             fclose(f);
217                             return 1;
218                          }
219                        else break;
220                     }
221                }
222           }
223      }
224    fclose(f);
225    WRN("Failed in /proc/self/maps");
226    return 0;
227 }
228 #endif
229
230 static int
231 _try_argv(Eina_Prefix *pfx, const char *argv0)
232 {
233    char *path, *p, *cp, *s;
234    int len, lenexe;
235    char buf[PATH_MAX], buf2[PATH_MAX], buf3[PATH_MAX];
236
237    DBG("Try argv0 = %s", argv0);
238    /* 1. is argv0 abs path? */
239 #ifdef _WIN32
240    if (evil_path_is_absolute(argv0))
241 #else
242    if (argv0[0] == DSEP_C)
243 #endif
244      {
245         DBG("Match arvg0 is full path: %s", argv0);
246         STRDUP_REP(pfx->exe_path, argv0);
247         if (access(pfx->exe_path, X_OK) == 0)
248           {
249              INF("Executable argv0 = %s", argv0);
250              return 1;
251           }
252         IF_FREE_NULL(pfx->exe_path);
253         DBG("Non existent argv0: %s", argv0);
254         return 0;
255      }
256    /* 2. relative path */
257    if (strchr(argv0, DSEP_C))
258      {
259         DBG("Relative path argv0: %s", argv0);
260         if (getcwd(buf3, sizeof(buf3)))
261           {
262              snprintf(buf2, sizeof(buf2), "%s" DSEP_S "%s", buf3, argv0);
263              DBG("Relative to CWD: %s", buf2);
264              if (realpath(buf2, buf))
265                {
266                   DBG("Realpath is: %s", buf);
267                   STRDUP_REP(pfx->exe_path, buf);
268                   if (access(pfx->exe_path, X_OK) == 0)
269                     {
270                        INF("Path %s is executable", pfx->exe_path);
271                        return 1;
272                     }
273                   DBG("Fail check for executable: %s", pfx->exe_path);
274                   IF_FREE_NULL(pfx->exe_path);
275                }
276           }
277      }
278    /* 3. argv0 no path - look in PATH */
279    DBG("Look for argv0=%s in $PATH", argv0);
280    path = getenv("PATH");
281    if (!path) return 0;
282    p = path;
283    cp = p;
284    lenexe = strlen(argv0);
285    while ((p = strchr(cp, PSEP_C)))
286      {
287         len = p - cp;
288         s = malloc(len + 1 + lenexe + 1);
289         if (s)
290           {
291              strncpy(s, cp, len);
292              s[len] = DSEP_C;
293              strcpy(s + len + 1, argv0);
294              DBG("Try path: %s", s);
295              if (realpath(s, buf))
296                {
297                   DBG("Realpath is: %s", buf);
298                   if (access(buf, X_OK) == 0)
299                     {
300                        STRDUP_REP(pfx->exe_path, buf);
301                        INF("Path %s is executable", pfx->exe_path);
302                        free(s);
303                        return 1;
304                     }
305                }
306              free(s);
307           }
308         cp = p + 1;
309      }
310    /* 4. big problems. arg[0] != executable - weird execution */
311    return 0;
312 }
313
314 static int
315 _get_env_var(char **var, const char *env, const char *prefix, const char *dir)
316 {
317    char buf[PATH_MAX];
318    const char *s = getenv(env);
319
320    DBG("Try env var %s", env);
321    if (s)
322      {
323         INF("Have env %s = %s", env, s);
324         STRDUP_REP(*var, s);
325         return 1;
326      }
327    else if (prefix)
328      {
329         snprintf(buf, sizeof(buf), "%s" DSEP_S "%s", prefix, dir);
330         INF("Have prefix %s = %s", prefix, buf);
331         STRDUP_REP(*var, buf);
332         return 1;
333      }
334    return 0;
335 }
336
337 static int
338 _get_env_vars(Eina_Prefix *pfx,
339               const char *envprefix,
340               const char *bindir,
341               const char *libdir,
342               const char *datadir,
343               const char *localedir)
344 {
345    char env[1024];
346    const char *s;
347    int ret = 0;
348
349    snprintf(env, sizeof(env), "%s_PREFIX", envprefix);
350    if ((s = getenv(env))) STRDUP_REP(pfx->prefix_path, s);
351    snprintf(env, sizeof(env), "%s_BIN_DIR", envprefix);
352    ret += _get_env_var(&pfx->prefix_path_bin, env, s, bindir);
353    snprintf(env, sizeof(env), "%s_LIB_DIR", envprefix);
354    ret += _get_env_var(&pfx->prefix_path_lib, env, s, libdir);
355    snprintf(env, sizeof(env), "%s_DATA_DIR", envprefix);
356    ret += _get_env_var(&pfx->prefix_path_data, env, s, datadir);
357    snprintf(env, sizeof(env), "%s_LOCALE_DIR", envprefix);
358    ret += _get_env_var(&pfx->prefix_path_locale, env, s, localedir);
359    return ret;
360 }
361
362 /**
363  * @endcond
364  */
365
366
367 /*============================================================================*
368  *                                 Global                                     *
369  *============================================================================*/
370
371
372 /*============================================================================*
373  *                                   API                                      *
374  *============================================================================*/
375
376
377 EAPI Eina_Prefix *
378 eina_prefix_new(const char *argv0, void *symbol, const char *envprefix,
379                 const char *sharedir, const char *magicsharefile,
380                 const char *pkg_bin, const char *pkg_lib,
381                 const char *pkg_data, const char *pkg_locale)
382 {
383    Eina_Prefix *pfx;
384    char *p, buf[4096], *tmp, *magic = NULL;
385    struct stat st;
386    const char *p1, *p2;
387    const char *pkg_bin_p = NULL;
388    const char *pkg_lib_p = NULL;
389    const char *pkg_data_p = NULL;
390    const char *pkg_locale_p = NULL;
391    const char *bindir = "bin";
392    const char *libdir = "lib";
393    const char *datadir = "share";
394    const char *localedir = "share";
395
396    DBG("EINA PREFIX: argv0=%s, symbol=%p, magicsharefile=%s, envprefix=%s",
397        argv0, symbol, magicsharefile, envprefix);
398    pfx = calloc(1, sizeof(Eina_Prefix));
399    if (!pfx) return NULL;
400
401    /* if provided with a share dir use datadir/sharedir as the share dir */
402    if (sharedir)
403      {
404         int len;
405
406         len = snprintf(buf, sizeof(buf), "%s" DSEP_S "%s", datadir, sharedir);
407         if (len > 0)
408           {
409 #ifdef _WIN32
410              /* on win32 convert / to \ for path here */
411              for (p = buf + strlen(datadir) + strlen(DSEP_S); *p; p++)
412                {
413                   if (*p == '/') *p = DSEP_C;
414                }
415 #endif
416              tmp = alloca(len + 1);
417              strcpy(tmp, buf);
418              datadir = tmp;
419           }
420      }
421    if (magicsharefile)
422      {
423         magic = alloca(strlen(magicsharefile));
424         strcpy(magic, magicsharefile);
425 #ifdef _WIN32
426         /* on win32 convert / to \ for path here */
427         for (p = magic; *p; p++)
428           {
429              if (*p == '/') *p = DSEP_C;
430           }
431 #endif
432      }
433
434    /* look at compile-time package bin/lib/datadir etc. and figure out the
435     * bin, lib and data dirs from these, if possible. i.e.
436     *   bin = /usr/local/bin
437     *   lib = /usr/local/lib
438     *   data = /usr/local/share/enlightenment
439     * thus they all have a common prefix string of /usr/local/ and
440     *   bindir = bin
441     *   libdir = lib
442     *   datadir = share/enlightenment
443     * this addresses things like libdir is lib64 or lib32 or other such
444     * junk distributions like to do so then:
445     *   bin = /usr/local/bin
446     *   lib = /usr/local/lib64
447     *   data = /usr/local/share/enlightenment
448     * then
449     *   bindir = bin
450     *   libdir = lib64
451     *   datadir = share/enlightennment
452     * in theory this should also work with debians new multiarch style like
453     *   bindir = bin
454     *   libdir = lib/i386-linux-gnu
455     *     or
456     *   libdir = lib/x86_64-linux-gnu
457     * all with a common prefix that can be relocated
458     */
459    /* 1. check last common char in bin and lib strings */
460    for (p1 = pkg_bin, p2 = pkg_lib; *p1 && *p2; p1++, p2++)
461      {
462         if (*p1 != *p2)
463           {
464              pkg_bin_p = p1;
465              pkg_lib_p = p2;
466              break;
467           }
468      }
469    /* 1. check last common char in bin and data strings */
470    for (p1 = pkg_bin, p2 = pkg_data; *p1 && *p2; p1++, p2++)
471      {
472         if (*p1 != *p2)
473           {
474              pkg_data_p = p2;
475              break;
476           }
477      }
478    /* 1. check last common char in bin and locale strings */
479    for (p1 = pkg_bin, p2 = pkg_locale; *p1 && *p2; p1++, p2++)
480      {
481         if (*p1 != *p2)
482           {
483              pkg_locale_p = p2;
484              break;
485           }
486      }
487    /* 2. if all the common string offsets match we compiled with a common prefix */
488    if (((pkg_bin_p - pkg_bin) == (pkg_lib_p - pkg_lib))
489        && ((pkg_bin_p - pkg_bin) == (pkg_data_p - pkg_data))
490        && ((pkg_bin_p - pkg_bin) == (pkg_locale_p - pkg_locale))
491       )
492      {
493         bindir = pkg_bin_p;
494         libdir = pkg_lib_p;
495         datadir = pkg_data_p;
496         localedir = pkg_locale_p;
497         DBG("Prefix relative bindir = %s", bindir);
498         DBG("Prefix relative libdir = %s", libdir);
499         DBG("Prefix relative datadir = %s", datadir);
500         DBG("Prefix relative localedir = %s", localedir);
501      }
502    /* 3. some galoot thought it awesome not to give us a common prefix at compile time
503     * so fall back to the compile time directories. we are no longer relocatable */
504    else
505      {
506         STRDUP_REP(pfx->prefix_path_bin, pkg_bin);
507         STRDUP_REP(pfx->prefix_path_lib, pkg_lib);
508         STRDUP_REP(pfx->prefix_path_data, pkg_data);
509         STRDUP_REP(pfx->prefix_path_locale, pkg_locale);
510         pfx->no_common_prefix = 1;
511         DBG("Can't work out a common prefix - compiled in fallback");
512      }
513
514    /* if user provides env vars - then use that or also more specific sub
515     * dirs for bin, lib, data and locale */
516    if ((envprefix) &&
517        (_get_env_vars(pfx, envprefix, bindir, libdir, datadir, localedir) > 0))
518      {
519         pfx->env_used = 1;
520         return pfx;
521      }
522
523 #ifdef HAVE_DLADDR
524    DBG("Try dladdr on %p", symbol);
525    if (symbol)
526      {
527         Dl_info info_dl;
528
529         if (dladdr(symbol, &info_dl))
530           {
531              DBG("Dlinfo worked");
532              if (info_dl.dli_fname)
533                {
534                   DBG("Dlinfo dli_fname = %s", info_dl.dli_fname);
535 # ifdef _WIN32
536                   if (evil_path_is_absolute(info_dl.dli_fname))
537 # else
538                   if (info_dl.dli_fname[0] == DSEP_C)
539 # endif
540                     {
541                        INF("Dlsym gave full path = %s", info_dl.dli_fname);
542                        STRDUP_REP(pfx->exe_path, info_dl.dli_fname);
543                     }
544                }
545           }
546      }
547 #endif
548    /* no env var - examine process and possible argv0 */
549    if ((argv0) && (!pfx->exe_path) && (symbol))
550      {
551 #ifndef _WIN32
552         if (!_try_proc(pfx, symbol))
553           {
554 #endif
555              if (!_try_argv(pfx, argv0))
556                {
557                   _fallback(pfx, pkg_bin, pkg_lib, pkg_data, pkg_locale,
558                             envprefix);
559                   return pfx;
560                }
561 #ifndef _WIN32
562           }
563 #endif
564      }
565    if (!pfx->exe_path)
566      {
567         WRN("Fallback - nothing found");
568         _fallback(pfx, pkg_bin, pkg_lib, pkg_data, pkg_locale, envprefix);
569         return pfx;
570      }
571    /* _exe_path is now a full absolute path TO this exe - figure out rest */
572    /*   if
573     * exe        = /blah/whatever/bin/exe
574     *   or
575     * exe        = /blah/whatever/lib/libexe.so
576     *   then
577     * prefix     = /blah/whatever
578     * bin_dir    = /blah/whatever/bin
579     * data_dir   = /blah/whatever/share/enlightenment
580     * lib_dir    = /blah/whatever/lib
581     * 
582     * new case - debian multiarch goop.
583     * exe        = /blah/whatever/lib/arch/libexe.so
584     */
585    DBG("From exe %s figure out the rest", pfx->exe_path);
586    p = strrchr(pfx->exe_path, DSEP_C);
587    if (p)
588      {
589         p--;
590         while (p >= pfx->exe_path)
591           {
592              if (*p == DSEP_C)
593                {
594                   if (pfx->prefix_path) free(pfx->prefix_path);
595                   pfx->prefix_path = malloc(p - pfx->exe_path + 1);
596                   if (pfx->prefix_path)
597                     {
598                        strncpy(pfx->prefix_path, pfx->exe_path,
599                                p - pfx->exe_path);
600                        pfx->prefix_path[p - pfx->exe_path] = 0;
601                        DBG("Have prefix = %s", pfx->prefix_path);
602
603                        /* bin */
604                        snprintf(buf, sizeof(buf), "%s" DSEP_S "%s",
605                                 pfx->prefix_path, bindir);
606                        STRDUP_REP(pfx->prefix_path_bin, buf);
607                        DBG("Have bin = %s", pfx->prefix_path_bin);
608                        /* lib */
609                        snprintf(buf, sizeof(buf), "%s" DSEP_S "%s",
610                                 pfx->prefix_path, libdir);
611                        STRDUP_REP(pfx->prefix_path_lib, buf);
612                        DBG("Have lib = %s", pfx->prefix_path_lib);
613                        /* locale */
614                        snprintf(buf, sizeof(buf), "%s" DSEP_S "%s",
615                                 pfx->prefix_path, localedir);
616                        STRDUP_REP(pfx->prefix_path_locale, buf);
617                        DBG("Have locale = %s", pfx->prefix_path_locale);
618                        /* check if magic file is there - then our guess is right */
619                        if (magic)
620                          {
621                             DBG("Magic = %s", magic);
622                             snprintf(buf, sizeof(buf),
623                                      "%s" DSEP_S "%s" DSEP_S "%s",
624                                      pfx->prefix_path, datadir, magic);
625                             DBG("Check in %s", buf);
626                          }
627                        if ((!magic) || (stat(buf, &st) == 0))
628                          {
629                             if (buf[0])
630                                DBG("Magic path %s stat passed", buf);
631                             else
632                                DBG("No magic file");
633                             snprintf(buf, sizeof(buf), "%s" DSEP_S "%s",
634                                      pfx->prefix_path, datadir);
635                             STRDUP_REP(pfx->prefix_path_data, buf);
636                          }
637                        /* magic file not there. time to start hunting! */
638                        else
639                          {
640                             if (buf[0])
641                               {
642                                  for (;p > pfx->exe_path; p--)
643                                    {
644                                       if (*p == DSEP_C)
645                                         {
646                                            p--;
647                                            break;
648                                         }
649                                    }
650                                  if (p > pfx->exe_path)
651                                    {
652                                       continue;
653                                       DBG("Go back one directory");
654                                    }
655                               }
656                             WRN("Magic failed");
657                             _fallback(pfx, pkg_bin, pkg_lib, pkg_data,
658                                       pkg_locale, envprefix);
659                          }
660                     }
661                   else
662                     {
663                        WRN("No Prefix path (alloc fail)");
664                        _fallback(pfx, pkg_bin, pkg_lib, pkg_data, pkg_locale,
665                                  envprefix);
666                     }
667                   return pfx;
668                }
669              p--;
670           }
671      }
672    WRN("Final fallback");
673    _fallback(pfx, pkg_bin, pkg_lib, pkg_data, pkg_locale, envprefix);
674    return pfx;
675 }
676
677 EAPI void
678 eina_prefix_free(Eina_Prefix *pfx)
679 {
680    if (!pfx) return;
681
682    IF_FREE_NULL(pfx->exe_path);
683    IF_FREE_NULL(pfx->prefix_path);
684    IF_FREE_NULL(pfx->prefix_path_bin);
685    IF_FREE_NULL(pfx->prefix_path_data);
686    IF_FREE_NULL(pfx->prefix_path_lib);
687    IF_FREE_NULL(pfx->prefix_path_locale);
688    free(pfx);
689 }
690
691 EAPI const char *
692 eina_prefix_get(Eina_Prefix *pfx)
693 {
694    if (!pfx) return "";
695    return pfx->prefix_path;
696 }
697
698 EAPI const char *
699 eina_prefix_bin_get(Eina_Prefix *pfx)
700 {
701    if (!pfx) return "";
702    return pfx->prefix_path_bin;
703 }
704
705 EAPI const char *
706 eina_prefix_lib_get(Eina_Prefix *pfx)
707 {
708    if (!pfx) return "";
709    return pfx->prefix_path_lib;
710 }
711
712 EAPI const char *
713 eina_prefix_data_get(Eina_Prefix *pfx)
714 {
715    if (!pfx) return "";
716    return pfx->prefix_path_data;
717 }
718
719 EAPI const char *
720 eina_prefix_locale_get(Eina_Prefix *pfx)
721 {
722    if (!pfx) return "";
723    return pfx->prefix_path_locale;
724 }
725
726 Eina_Bool
727 eina_prefix_init(void)
728 {
729    _eina_prefix_log_dom = eina_log_domain_register("eina_prefix",
730                                                    EINA_LOG_COLOR_DEFAULT);
731    if (_eina_prefix_log_dom < 0)
732      {
733         EINA_LOG_ERR("Could not register log domain: eina_prefix");
734         return EINA_FALSE;
735      }
736
737    return EINA_TRUE;
738 }
739
740 Eina_Bool
741 eina_prefix_shutdown(void)
742 {
743    eina_log_domain_unregister(_eina_prefix_log_dom);
744    _eina_prefix_log_dom = -1;
745    return EINA_TRUE;
746 }