diff options
author | David Walter Seikel | 2012-01-04 18:41:13 +1000 |
---|---|---|
committer | David Walter Seikel | 2012-01-04 18:41:13 +1000 |
commit | dd7595a3475407a7fa96a97393bae8c5220e8762 (patch) | |
tree | e341e911d7eb911a51684a7412ef7f7c7605d28e /libraries/eina/src/lib/eina_prefix.c | |
parent | Add the skeleton. (diff) | |
download | SledjHamr-dd7595a3475407a7fa96a97393bae8c5220e8762.zip SledjHamr-dd7595a3475407a7fa96a97393bae8c5220e8762.tar.gz SledjHamr-dd7595a3475407a7fa96a97393bae8c5220e8762.tar.bz2 SledjHamr-dd7595a3475407a7fa96a97393bae8c5220e8762.tar.xz |
Add the base Enlightenment Foundation Libraries - eina, eet, evas, ecore, embryo, and edje.
Note that embryo wont be used, but I'm not sure yet if you can build edje without it.
Diffstat (limited to '')
-rw-r--r-- | libraries/eina/src/lib/eina_prefix.c | 727 |
1 files changed, 727 insertions, 0 deletions
diff --git a/libraries/eina/src/lib/eina_prefix.c b/libraries/eina/src/lib/eina_prefix.c new file mode 100644 index 0000000..9445222 --- /dev/null +++ b/libraries/eina/src/lib/eina_prefix.c | |||
@@ -0,0 +1,727 @@ | |||
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 __GNUC__ | ||
34 | # define alloca __builtin_alloca | ||
35 | #elif defined _AIX | ||
36 | # define alloca __alloca | ||
37 | #elif defined _MSC_VER | ||
38 | # include <malloc.h> | ||
39 | # define alloca _alloca | ||
40 | #else | ||
41 | # ifndef 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 | fprintf(stderr, | ||
154 | "WARNING: Could not determine its installed prefix for '%s'\n" | ||
155 | " so am falling back on the compiled in default:\n" | ||
156 | " %s\n" | ||
157 | " implied by the following:\n" | ||
158 | " bindir = %s\n" | ||
159 | " libdir = %s\n" | ||
160 | " datadir = %s\n" | ||
161 | " localedir = %s\n" | ||
162 | " Try setting the following environment variables:\n" | ||
163 | " %s_PREFIX - points to the base prefix of install\n" | ||
164 | " or the next 4 variables\n" | ||
165 | " %s_BIN_DIR - provide a specific binary directory\n" | ||
166 | " %s_LIB_DIR - provide a specific library directory\n" | ||
167 | " %s_DATA_DIR - provide a specific data directory\n" | ||
168 | " %s_LOCALE_DIR - provide a specific locale directory\n" | ||
169 | , envprefix, | ||
170 | pfx->prefix_path, pkg_bin, pkg_lib, pkg_data, pkg_locale, | ||
171 | envprefix, envprefix, envprefix, envprefix, envprefix); | ||
172 | pfx->fallback = 1; | ||
173 | return 1; | ||
174 | } | ||
175 | |||
176 | #ifndef _WIN32 | ||
177 | static int | ||
178 | _try_proc(Eina_Prefix *pfx, void *symbol) | ||
179 | { | ||
180 | FILE *f; | ||
181 | char buf[4096]; | ||
182 | |||
183 | DBG("Try /proc/self/maps"); | ||
184 | f = fopen("/proc/self/maps", "rb"); | ||
185 | if (!f) return 0; | ||
186 | DBG("Exists /proc/self/maps"); | ||
187 | while (fgets(buf, sizeof(buf), f)) | ||
188 | { | ||
189 | int len; | ||
190 | char *p, mode[5] = ""; | ||
191 | unsigned long ptr1 = 0, ptr2 = 0; | ||
192 | |||
193 | len = strlen(buf); | ||
194 | if (buf[len - 1] == '\n') | ||
195 | { | ||
196 | buf[len - 1] = 0; | ||
197 | len--; | ||
198 | } | ||
199 | if (sscanf(buf, "%lx-%lx %4s", &ptr1, &ptr2, mode) == 3) | ||
200 | { | ||
201 | if (!strcmp(mode, "r-xp")) | ||
202 | { | ||
203 | if (((void *)ptr1 <= symbol) && (symbol < (void *)ptr2)) | ||
204 | { | ||
205 | DBG("Found in /proc/self/maps: %s", buf); | ||
206 | p = strchr(buf, '/'); | ||
207 | if (p) | ||
208 | { | ||
209 | DBG("Found in /proc/self/maps: found last /"); | ||
210 | if (len > 10) | ||
211 | { | ||
212 | if (!strcmp(buf + len - 10, " (deleted)")) | ||
213 | buf[len - 10] = 0; | ||
214 | } | ||
215 | STRDUP_REP(pfx->exe_path, p); | ||
216 | INF("Found in /proc/self/maps: guess exe path is %s", pfx->exe_path); | ||
217 | fclose(f); | ||
218 | return 1; | ||
219 | } | ||
220 | else break; | ||
221 | } | ||
222 | } | ||
223 | } | ||
224 | } | ||
225 | fclose(f); | ||
226 | WRN("Failed in /proc/self/maps"); | ||
227 | return 0; | ||
228 | } | ||
229 | #endif | ||
230 | |||
231 | static int | ||
232 | _try_argv(Eina_Prefix *pfx, const char *argv0) | ||
233 | { | ||
234 | char *path, *p, *cp, *s; | ||
235 | int len, lenexe; | ||
236 | char buf[PATH_MAX], buf2[PATH_MAX], buf3[PATH_MAX]; | ||
237 | |||
238 | DBG("Try argv0 = %s", argv0); | ||
239 | /* 1. is argv0 abs path? */ | ||
240 | #ifdef _WIN32 | ||
241 | if (argv0[0] && (argv0[1] == ':')) | ||
242 | #else | ||
243 | if (argv0[0] == DSEP_C) | ||
244 | #endif | ||
245 | { | ||
246 | DBG("Match arvg0 is full path: %s", argv0); | ||
247 | STRDUP_REP(pfx->exe_path, argv0); | ||
248 | if (access(pfx->exe_path, X_OK) == 0) | ||
249 | { | ||
250 | INF("Executable argv0 = %s", argv0); | ||
251 | return 1; | ||
252 | } | ||
253 | IF_FREE_NULL(pfx->exe_path); | ||
254 | DBG("Non existent argv0: %s", argv0); | ||
255 | return 0; | ||
256 | } | ||
257 | /* 2. relative path */ | ||
258 | if (strchr(argv0, DSEP_C)) | ||
259 | { | ||
260 | DBG("Relative path argv0: %s", argv0); | ||
261 | if (getcwd(buf3, sizeof(buf3))) | ||
262 | { | ||
263 | snprintf(buf2, sizeof(buf2), "%s" DSEP_S "%s", buf3, argv0); | ||
264 | DBG("Relative to CWD: %s", buf2); | ||
265 | if (realpath(buf2, buf)) | ||
266 | { | ||
267 | DBG("Realpath is: %s", buf); | ||
268 | STRDUP_REP(pfx->exe_path, buf); | ||
269 | if (access(pfx->exe_path, X_OK) == 0) | ||
270 | { | ||
271 | INF("Path %s is executable", pfx->exe_path); | ||
272 | return 1; | ||
273 | } | ||
274 | DBG("Fail check for executable: %s", pfx->exe_path); | ||
275 | IF_FREE_NULL(pfx->exe_path); | ||
276 | } | ||
277 | } | ||
278 | } | ||
279 | /* 3. argv0 no path - look in PATH */ | ||
280 | DBG("Look for argv0=%s in $PATH", argv0); | ||
281 | path = getenv("PATH"); | ||
282 | if (!path) return 0; | ||
283 | p = path; | ||
284 | cp = p; | ||
285 | lenexe = strlen(argv0); | ||
286 | while ((p = strchr(cp, PSEP_C))) | ||
287 | { | ||
288 | len = p - cp; | ||
289 | s = malloc(len + 1 + lenexe + 1); | ||
290 | if (s) | ||
291 | { | ||
292 | strncpy(s, cp, len); | ||
293 | s[len] = DSEP_C; | ||
294 | strcpy(s + len + 1, argv0); | ||
295 | DBG("Try path: %s", s); | ||
296 | if (realpath(s, buf)) | ||
297 | { | ||
298 | DBG("Realpath is: %s", buf); | ||
299 | if (access(buf, X_OK) == 0) | ||
300 | { | ||
301 | STRDUP_REP(pfx->exe_path, buf); | ||
302 | INF("Path %s is executable", pfx->exe_path); | ||
303 | free(s); | ||
304 | return 1; | ||
305 | } | ||
306 | } | ||
307 | free(s); | ||
308 | } | ||
309 | cp = p + 1; | ||
310 | } | ||
311 | /* 4. big problems. arg[0] != executable - weird execution */ | ||
312 | return 0; | ||
313 | } | ||
314 | |||
315 | static int | ||
316 | _get_env_var(char **var, const char *env, const char *prefix, const char *dir) | ||
317 | { | ||
318 | char buf[PATH_MAX]; | ||
319 | const char *s = getenv(env); | ||
320 | |||
321 | DBG("Try env var %s", env); | ||
322 | if (s) | ||
323 | { | ||
324 | INF("Have env %s = %s", env, s); | ||
325 | STRDUP_REP(*var, s); | ||
326 | return 1; | ||
327 | } | ||
328 | else if (prefix) | ||
329 | { | ||
330 | snprintf(buf, sizeof(buf), "%s" DSEP_S "%s", prefix, dir); | ||
331 | INF("Have prefix %s = %s", prefix, buf); | ||
332 | STRDUP_REP(*var, buf); | ||
333 | return 1; | ||
334 | } | ||
335 | return 0; | ||
336 | } | ||
337 | |||
338 | static int | ||
339 | _get_env_vars(Eina_Prefix *pfx, | ||
340 | const char *envprefix, | ||
341 | const char *bindir, | ||
342 | const char *libdir, | ||
343 | const char *datadir, | ||
344 | const char *localedir) | ||
345 | { | ||
346 | char env[1024]; | ||
347 | const char *s; | ||
348 | int ret = 0; | ||
349 | |||
350 | snprintf(env, sizeof(env), "%s_PREFIX", envprefix); | ||
351 | if ((s = getenv(env))) STRDUP_REP(pfx->prefix_path, s); | ||
352 | snprintf(env, sizeof(env), "%s_BIN_DIR", envprefix); | ||
353 | ret += _get_env_var(&pfx->prefix_path_bin, env, s, bindir); | ||
354 | snprintf(env, sizeof(env), "%s_LIB_DIR", envprefix); | ||
355 | ret += _get_env_var(&pfx->prefix_path_lib, env, s, libdir); | ||
356 | snprintf(env, sizeof(env), "%s_DATA_DIR", envprefix); | ||
357 | ret += _get_env_var(&pfx->prefix_path_data, env, s, datadir); | ||
358 | snprintf(env, sizeof(env), "%s_LOCALE_DIR", envprefix); | ||
359 | ret += _get_env_var(&pfx->prefix_path_locale, env, s, localedir); | ||
360 | return ret; | ||
361 | } | ||
362 | |||
363 | /** | ||
364 | * @endcond | ||
365 | */ | ||
366 | |||
367 | |||
368 | /*============================================================================* | ||
369 | * Global * | ||
370 | *============================================================================*/ | ||
371 | |||
372 | |||
373 | /*============================================================================* | ||
374 | * API * | ||
375 | *============================================================================*/ | ||
376 | |||
377 | |||
378 | EAPI Eina_Prefix * | ||
379 | eina_prefix_new(const char *argv0, void *symbol, const char *envprefix, | ||
380 | const char *sharedir, const char *magicsharefile, | ||
381 | const char *pkg_bin, const char *pkg_lib, | ||
382 | const char *pkg_data, const char *pkg_locale) | ||
383 | { | ||
384 | Eina_Prefix *pfx; | ||
385 | char *p, buf[4096], *tmp, *magic = NULL; | ||
386 | struct stat st; | ||
387 | const char *p1, *p2; | ||
388 | const char *pkg_bin_p = NULL; | ||
389 | const char *pkg_lib_p = NULL; | ||
390 | const char *pkg_data_p = NULL; | ||
391 | const char *pkg_locale_p = NULL; | ||
392 | const char *bindir = "bin"; | ||
393 | const char *libdir = "lib"; | ||
394 | const char *datadir = "share"; | ||
395 | const char *localedir = "share"; | ||
396 | |||
397 | DBG("EINA PREFIX: argv0=%s, symbol=%p, magicsharefile=%s, envprefix=%s", | ||
398 | argv0, symbol, magicsharefile, envprefix); | ||
399 | pfx = calloc(1, sizeof(Eina_Prefix)); | ||
400 | if (!pfx) return NULL; | ||
401 | |||
402 | /* if provided with a share dir use datadir/sharedir as the share dir */ | ||
403 | if (sharedir) | ||
404 | { | ||
405 | int len; | ||
406 | |||
407 | len = snprintf(buf, sizeof(buf), "%s" DSEP_S "%s", datadir, sharedir); | ||
408 | if (len > 0) | ||
409 | { | ||
410 | #ifdef _WIN32 | ||
411 | /* on win32 convert / to \ for path here */ | ||
412 | for (p = buf + strlen(datadir) + strlen(DSEP_S); *p; p++) | ||
413 | { | ||
414 | if (*p == '/') *p = DSEP_C; | ||
415 | } | ||
416 | #endif | ||
417 | tmp = alloca(len + 1); | ||
418 | strcpy(tmp, buf); | ||
419 | datadir = tmp; | ||
420 | } | ||
421 | } | ||
422 | if (magicsharefile) | ||
423 | { | ||
424 | magic = alloca(strlen(magicsharefile)); | ||
425 | strcpy(magic, magicsharefile); | ||
426 | #ifdef _WIN32 | ||
427 | /* on win32 convert / to \ for path here */ | ||
428 | for (p = magic; *p; p++) | ||
429 | { | ||
430 | if (*p == '/') *p = DSEP_C; | ||
431 | } | ||
432 | #endif | ||
433 | } | ||
434 | |||
435 | /* look at compile-time package bin/lib/datadir etc. and figure out the | ||
436 | * bin, lib and data dirs from these, if possible. i.e. | ||
437 | * bin = /usr/local/bin | ||
438 | * lib = /usr/local/lib | ||
439 | * data = /usr/local/share/enlightenment | ||
440 | * thus they all have a common prefix string of /usr/local/ and | ||
441 | * bindir = bin | ||
442 | * libdir = lib | ||
443 | * datadir = share/enlightenment | ||
444 | * this addresses things like libdir is lib64 or lib32 or other such | ||
445 | * junk distributions like to do so then: | ||
446 | * bin = /usr/local/bin | ||
447 | * lib = /usr/local/lib64 | ||
448 | * data = /usr/local/share/enlightenment | ||
449 | * then | ||
450 | * bindir = bin | ||
451 | * libdir = lib64 | ||
452 | * datadir = share/enlightennment | ||
453 | * in theory this should also work with debians new multiarch style like | ||
454 | * bindir = bin | ||
455 | * libdir = lib/i386-linux-gnu | ||
456 | * or | ||
457 | * libdir = lib/x86_64-linux-gnu | ||
458 | * all with a common prefix that can be relocated | ||
459 | */ | ||
460 | /* 1. check last common char in bin and lib strings */ | ||
461 | for (p1 = pkg_bin, p2 = pkg_lib; *p1 && *p2; p1++, p2++) | ||
462 | { | ||
463 | if (*p1 != *p2) | ||
464 | { | ||
465 | pkg_bin_p = p1; | ||
466 | pkg_lib_p = p2; | ||
467 | break; | ||
468 | } | ||
469 | } | ||
470 | /* 1. check last common char in bin and data strings */ | ||
471 | for (p1 = pkg_bin, p2 = pkg_data; *p1 && *p2; p1++, p2++) | ||
472 | { | ||
473 | if (*p1 != *p2) | ||
474 | { | ||
475 | pkg_data_p = p2; | ||
476 | break; | ||
477 | } | ||
478 | } | ||
479 | /* 1. check last common char in bin and locale strings */ | ||
480 | for (p1 = pkg_bin, p2 = pkg_locale; *p1 && *p2; p1++, p2++) | ||
481 | { | ||
482 | if (*p1 != *p2) | ||
483 | { | ||
484 | pkg_locale_p = p2; | ||
485 | break; | ||
486 | } | ||
487 | } | ||
488 | /* 2. if all the common string offsets match we compiled with a common prefix */ | ||
489 | if (((pkg_bin_p - pkg_bin) == (pkg_lib_p - pkg_lib)) | ||
490 | && ((pkg_bin_p - pkg_bin) == (pkg_data_p - pkg_data)) | ||
491 | && ((pkg_bin_p - pkg_bin) == (pkg_locale_p - pkg_locale)) | ||
492 | ) | ||
493 | { | ||
494 | bindir = pkg_bin_p; | ||
495 | libdir = pkg_lib_p; | ||
496 | datadir = pkg_data_p; | ||
497 | localedir = pkg_locale_p; | ||
498 | DBG("Prefix relative bindir = %s", bindir); | ||
499 | DBG("Prefix relative libdir = %s", libdir); | ||
500 | DBG("Prefix relative datadir = %s", datadir); | ||
501 | DBG("Prefix relative localedir = %s", localedir); | ||
502 | } | ||
503 | /* 3. some galoot thought it awesome not to give us a common prefix at compile time | ||
504 | * so fall back to the compile time directories. we are no longer relocatable */ | ||
505 | else | ||
506 | { | ||
507 | STRDUP_REP(pfx->prefix_path_bin, pkg_bin); | ||
508 | STRDUP_REP(pfx->prefix_path_lib, pkg_lib); | ||
509 | STRDUP_REP(pfx->prefix_path_data, pkg_data); | ||
510 | STRDUP_REP(pfx->prefix_path_locale, pkg_locale); | ||
511 | pfx->no_common_prefix = 1; | ||
512 | DBG("Can't work out a common prefix - compiled in fallback"); | ||
513 | } | ||
514 | |||
515 | /* if user provides env vars - then use that or also more specific sub | ||
516 | * dirs for bin, lib, data and locale */ | ||
517 | if ((envprefix) && | ||
518 | (_get_env_vars(pfx, envprefix, bindir, libdir, datadir, localedir) > 0)) | ||
519 | { | ||
520 | pfx->env_used = 1; | ||
521 | return pfx; | ||
522 | } | ||
523 | |||
524 | #ifdef HAVE_DLADDR | ||
525 | DBG("Try dladdr on %p", symbol); | ||
526 | if (symbol) | ||
527 | { | ||
528 | Dl_info info_dl; | ||
529 | |||
530 | if (dladdr(symbol, &info_dl)) | ||
531 | { | ||
532 | DBG("Dlinfo worked"); | ||
533 | if (info_dl.dli_fname) | ||
534 | { | ||
535 | DBG("Dlinfo dli_fname = %s", info_dl.dli_fname); | ||
536 | # ifdef _WIN32 | ||
537 | if (info_dl.dli_fname[0] && (info_dl.dli_fname[1] == ':')) | ||
538 | # else | ||
539 | if (info_dl.dli_fname[0] == DSEP_C) | ||
540 | # endif | ||
541 | { | ||
542 | INF("Dlsym gave full path = %s", info_dl.dli_fname); | ||
543 | STRDUP_REP(pfx->exe_path, info_dl.dli_fname); | ||
544 | } | ||
545 | } | ||
546 | } | ||
547 | } | ||
548 | #endif | ||
549 | /* no env var - examine process and possible argv0 */ | ||
550 | if ((argv0) && (!pfx->exe_path) && (symbol)) | ||
551 | { | ||
552 | #ifndef _WIN32 | ||
553 | if (!_try_proc(pfx, symbol)) | ||
554 | { | ||
555 | #endif | ||
556 | if (!_try_argv(pfx, argv0)) | ||
557 | { | ||
558 | _fallback(pfx, pkg_bin, pkg_lib, pkg_data, pkg_locale, | ||
559 | envprefix); | ||
560 | return pfx; | ||
561 | } | ||
562 | #ifndef _WIN32 | ||
563 | } | ||
564 | #endif | ||
565 | } | ||
566 | if (!pfx->exe_path) | ||
567 | { | ||
568 | WRN("Fallback - nothing found"); | ||
569 | _fallback(pfx, pkg_bin, pkg_lib, pkg_data, pkg_locale, envprefix); | ||
570 | return pfx; | ||
571 | } | ||
572 | /* _exe_path is now a full absolute path TO this exe - figure out rest */ | ||
573 | /* if | ||
574 | * exe = /blah/whatever/bin/exe | ||
575 | * or | ||
576 | * exe = /blah/whatever/lib/libexe.so | ||
577 | * then | ||
578 | * prefix = /blah/whatever | ||
579 | * bin_dir = /blah/whatever/bin | ||
580 | * data_dir = /blah/whatever/share/enlightenment | ||
581 | * lib_dir = /blah/whatever/lib | ||
582 | */ | ||
583 | DBG("From exe %s figure out the rest", pfx->exe_path); | ||
584 | p = strrchr(pfx->exe_path, DSEP_C); | ||
585 | if (p) | ||
586 | { | ||
587 | p--; | ||
588 | while (p >= pfx->exe_path) | ||
589 | { | ||
590 | if (*p == DSEP_C) | ||
591 | { | ||
592 | pfx->prefix_path = malloc(p - pfx->exe_path + 1); | ||
593 | if (pfx->prefix_path) | ||
594 | { | ||
595 | strncpy(pfx->prefix_path, pfx->exe_path, | ||
596 | p - pfx->exe_path); | ||
597 | pfx->prefix_path[p - pfx->exe_path] = 0; | ||
598 | DBG("Have prefix = %s", pfx->prefix_path); | ||
599 | |||
600 | /* bin */ | ||
601 | snprintf(buf, sizeof(buf), "%s" DSEP_S "%s", | ||
602 | pfx->prefix_path, bindir); | ||
603 | STRDUP_REP(pfx->prefix_path_bin, buf); | ||
604 | DBG("Have bin = %s", pfx->prefix_path_bin); | ||
605 | /* lib */ | ||
606 | snprintf(buf, sizeof(buf), "%s" DSEP_S "%s", | ||
607 | pfx->prefix_path, libdir); | ||
608 | STRDUP_REP(pfx->prefix_path_lib, buf); | ||
609 | DBG("Have lib = %s", pfx->prefix_path_lib); | ||
610 | /* locale */ | ||
611 | snprintf(buf, sizeof(buf), "%s" DSEP_S "%s", | ||
612 | pfx->prefix_path, localedir); | ||
613 | STRDUP_REP(pfx->prefix_path_locale, buf); | ||
614 | DBG("Have locale = %s", pfx->prefix_path_locale); | ||
615 | /* check if magic file is there - then our guess is right */ | ||
616 | if (magic) | ||
617 | { | ||
618 | DBG("Magic = %s", magic); | ||
619 | snprintf(buf, sizeof(buf), | ||
620 | "%s" DSEP_S "%s" DSEP_S "%s", | ||
621 | pfx->prefix_path, datadir, magic); | ||
622 | DBG("Check in %s", buf); | ||
623 | } | ||
624 | if ((!magic) || (stat(buf, &st) == 0)) | ||
625 | { | ||
626 | if (buf[0]) | ||
627 | DBG("Magic path %s stat passed", buf); | ||
628 | else | ||
629 | DBG("No magic file"); | ||
630 | snprintf(buf, sizeof(buf), "%s" DSEP_S "%s", | ||
631 | pfx->prefix_path, datadir); | ||
632 | STRDUP_REP(pfx->prefix_path_data, buf); | ||
633 | } | ||
634 | /* magic file not there. time to start hunting! */ | ||
635 | else | ||
636 | { | ||
637 | WRN("Magic failed"); | ||
638 | _fallback(pfx, pkg_bin, pkg_lib, pkg_data, | ||
639 | pkg_locale, envprefix); | ||
640 | } | ||
641 | } | ||
642 | else | ||
643 | { | ||
644 | WRN("No Prefix path (alloc fail)"); | ||
645 | _fallback(pfx, pkg_bin, pkg_lib, pkg_data, pkg_locale, | ||
646 | envprefix); | ||
647 | } | ||
648 | return pfx; | ||
649 | } | ||
650 | p--; | ||
651 | } | ||
652 | } | ||
653 | WRN("Final fallback"); | ||
654 | _fallback(pfx, pkg_bin, pkg_lib, pkg_data, pkg_locale, envprefix); | ||
655 | return pfx; | ||
656 | } | ||
657 | |||
658 | EAPI void | ||
659 | eina_prefix_free(Eina_Prefix *pfx) | ||
660 | { | ||
661 | if (!pfx) return; | ||
662 | |||
663 | IF_FREE_NULL(pfx->exe_path); | ||
664 | IF_FREE_NULL(pfx->prefix_path); | ||
665 | IF_FREE_NULL(pfx->prefix_path_bin); | ||
666 | IF_FREE_NULL(pfx->prefix_path_data); | ||
667 | IF_FREE_NULL(pfx->prefix_path_lib); | ||
668 | IF_FREE_NULL(pfx->prefix_path_locale); | ||
669 | free(pfx); | ||
670 | } | ||
671 | |||
672 | EAPI const char * | ||
673 | eina_prefix_get(Eina_Prefix *pfx) | ||
674 | { | ||
675 | if (!pfx) return ""; | ||
676 | return pfx->prefix_path; | ||
677 | } | ||
678 | |||
679 | EAPI const char * | ||
680 | eina_prefix_bin_get(Eina_Prefix *pfx) | ||
681 | { | ||
682 | if (!pfx) return ""; | ||
683 | return pfx->prefix_path_bin; | ||
684 | } | ||
685 | |||
686 | EAPI const char * | ||
687 | eina_prefix_lib_get(Eina_Prefix *pfx) | ||
688 | { | ||
689 | if (!pfx) return ""; | ||
690 | return pfx->prefix_path_lib; | ||
691 | } | ||
692 | |||
693 | EAPI const char * | ||
694 | eina_prefix_data_get(Eina_Prefix *pfx) | ||
695 | { | ||
696 | if (!pfx) return ""; | ||
697 | return pfx->prefix_path_data; | ||
698 | } | ||
699 | |||
700 | EAPI const char * | ||
701 | eina_prefix_locale_get(Eina_Prefix *pfx) | ||
702 | { | ||
703 | if (!pfx) return ""; | ||
704 | return pfx->prefix_path_locale; | ||
705 | } | ||
706 | |||
707 | Eina_Bool | ||
708 | eina_prefix_init(void) | ||
709 | { | ||
710 | _eina_prefix_log_dom = eina_log_domain_register("eina_prefix", | ||
711 | EINA_LOG_COLOR_DEFAULT); | ||
712 | if (_eina_prefix_log_dom < 0) | ||
713 | { | ||
714 | EINA_LOG_ERR("Could not register log domain: eina_prefix"); | ||
715 | return EINA_FALSE; | ||
716 | } | ||
717 | |||
718 | return EINA_TRUE; | ||
719 | } | ||
720 | |||
721 | Eina_Bool | ||
722 | eina_prefix_shutdown(void) | ||
723 | { | ||
724 | eina_log_domain_unregister(_eina_prefix_log_dom); | ||
725 | _eina_prefix_log_dom = -1; | ||
726 | return EINA_TRUE; | ||
727 | } | ||