Add Tizen 2.0 packaging
[profile/ivi/efreet.git] / src / lib / efreet_base.c
1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4
5 #include "efreet_alloca.h"
6
7 #include <unistd.h>
8 #include <ctype.h>
9
10 #ifdef _WIN32
11 # include <winsock2.h>
12 #endif
13
14 /* define macros and variable for using the eina logging system  */
15 #define EFREET_MODULE_LOG_DOM _efreet_base_log_dom
16 static int _efreet_base_log_dom = -1;
17
18 #include "Efreet.h"
19 #include "efreet_private.h"
20
21 static Efreet_Version _version = { VMAJ, VMIN, VMIC, VREV };
22 EAPI Efreet_Version *efreet_version = &_version;
23
24 #ifdef _WIN32
25 # define EFREET_PATH_SEP ';'
26 #else
27 # define EFREET_PATH_SEP ':'
28 #endif
29
30 static const char *efreet_home_dir = NULL;
31 static const char *xdg_data_home = NULL;
32 static const char *xdg_config_home = NULL;
33 static const char *xdg_cache_home = NULL;
34 static Eina_List  *xdg_data_dirs = NULL;
35 static Eina_List  *xdg_config_dirs = NULL;
36 static const char *xdg_desktop_dir = NULL;
37 static const char *hostname = NULL;
38
39 static const char *efreet_dir_get(const char *key, const char *fallback);
40 static Eina_List  *efreet_dirs_get(const char *key,
41                                         const char *fallback);
42 static const char *efreet_user_dir_get(const char *key, const char *fallback);
43
44 /**
45  * @internal
46  * @return Returns @c 1 on success or @c 0 on failure
47  * @brief Initializes the efreet base settings
48  */
49 int
50 efreet_base_init(void)
51 {
52     _efreet_base_log_dom = eina_log_domain_register
53       ("efreet_base", EFREET_DEFAULT_LOG_COLOR);
54     if (_efreet_base_log_dom < 0)
55     {
56         EINA_LOG_ERR("Efreet: Could not create a log domain for efreet_base.\n");
57         return 0;
58     }
59     return 1;
60 }
61
62 /**
63  * @internal
64  * @return Returns no value
65  * @brief Cleans up the efreet base settings system
66  */
67 void
68 efreet_base_shutdown(void)
69 {
70     IF_RELEASE(efreet_home_dir);
71     IF_RELEASE(xdg_desktop_dir);
72     IF_RELEASE(xdg_data_home);
73     IF_RELEASE(xdg_config_home);
74     IF_RELEASE(xdg_cache_home);
75
76     IF_FREE_LIST(xdg_data_dirs, eina_stringshare_del);
77     IF_FREE_LIST(xdg_config_dirs, eina_stringshare_del);
78
79     IF_RELEASE(hostname);
80
81     eina_log_domain_unregister(_efreet_base_log_dom);
82     _efreet_base_log_dom = -1;
83 }
84
85 /**
86  * @internal
87  * @return Returns the users home directory
88  * @brief Gets the users home directory and returns it.
89  */
90 const char *
91 efreet_home_dir_get(void)
92 {
93     if (efreet_home_dir) return efreet_home_dir;
94
95     efreet_home_dir = getenv("HOME");
96 #ifdef _WIN32
97     if (!efreet_home_dir || efreet_home_dir[0] == '\0')
98         efreet_home_dir = getenv("USERPROFILE");
99 #endif
100     if (!efreet_home_dir || efreet_home_dir[0] == '\0')
101         efreet_home_dir = "/tmp";
102
103     efreet_home_dir = eina_stringshare_add(efreet_home_dir);
104
105     return efreet_home_dir;
106 }
107
108 EAPI const char *
109 efreet_desktop_dir_get(void)
110 {
111     if (xdg_desktop_dir) return xdg_desktop_dir;
112     xdg_desktop_dir = efreet_user_dir_get("XDG_DESKTOP_DIR", _("Desktop"));
113     return xdg_desktop_dir;
114 }
115
116 EAPI const char *
117 efreet_data_home_get(void)
118 {
119     if (xdg_data_home) return xdg_data_home;
120     xdg_data_home = efreet_dir_get("XDG_DATA_HOME", "/.local/share");
121     return xdg_data_home;
122 }
123
124 EAPI Eina_List *
125 efreet_data_dirs_get(void)
126 {
127 #ifdef _WIN32
128     char buf[4096];
129 #endif
130
131     if (xdg_data_dirs) return xdg_data_dirs;
132
133 #ifdef _WIN32
134     snprintf(buf, 4096, "%s\\Efl;" PACKAGE_DATA_DIR ";/usr/share;/usr/local/share", getenv("APPDATA"));
135     xdg_data_dirs = efreet_dirs_get("XDG_DATA_DIRS", buf);
136 #else
137     xdg_data_dirs = efreet_dirs_get("XDG_DATA_DIRS",
138                             PACKAGE_DATA_DIR ":/usr/share:/usr/local/share");
139 #endif
140     return xdg_data_dirs;
141 }
142
143 EAPI const char *
144 efreet_config_home_get(void)
145 {
146     if (xdg_config_home) return xdg_config_home;
147     xdg_config_home = efreet_dir_get("XDG_CONFIG_HOME", "/.config");
148     return xdg_config_home;
149 }
150
151 EAPI Eina_List *
152 efreet_config_dirs_get(void)
153 {
154     if (xdg_config_dirs) return xdg_config_dirs;
155     xdg_config_dirs = efreet_dirs_get("XDG_CONFIG_DIRS", "/etc/xdg");
156     return xdg_config_dirs;
157 }
158
159 EAPI const char *
160 efreet_cache_home_get(void)
161 {
162     if (xdg_cache_home) return xdg_cache_home;
163     xdg_cache_home = efreet_dir_get("XDG_CACHE_HOME", "/.cache");
164     return xdg_cache_home;
165 }
166
167 EAPI const char *
168 efreet_hostname_get(void)
169 {
170     char buf[256];
171
172     if (hostname) return hostname;
173     if (gethostname(buf, sizeof(buf)) < 0)
174         hostname = eina_stringshare_add("");
175     else
176         hostname = eina_stringshare_add(buf);
177     return hostname;
178 }
179
180 void
181 efreet_dirs_reset(void)
182 {
183     eina_stringshare_replace(&xdg_desktop_dir, NULL);
184 }
185
186 /**
187  * @internal
188  * @param key The environment key to lookup
189  * @param fallback The fallback value to use
190  * @return Returns the directory related to the given key or the fallback
191  * @brief This tries to determine the correct directory name given the
192  * environment key @a key and fallbacks @a fallback.
193  */
194 static const char *
195 efreet_dir_get(const char *key, const char *fallback)
196 {
197     char *dir;
198     const char *t;
199
200     dir = getenv(key);
201     if (!dir || dir[0] == '\0')
202     {
203         int len;
204         const char *user;
205
206         user = efreet_home_dir_get();
207         len = strlen(user) + strlen(fallback) + 1;
208         dir = alloca(len);
209         snprintf(dir, len, "%s%s", user, fallback);
210
211         t = eina_stringshare_add(dir);
212     }
213     else t = eina_stringshare_add(dir);
214
215     return t;
216 }
217
218 /**
219  * @internal
220  * @param key The environment key to lookup
221  * @param fallback The fallback value to use
222  * @return Returns a list of directories specified by the given key @a key
223  * or from the list of fallbacks in @a fallback.
224  * @brief Creates a list of directories as given in the environment key @a
225  * key or from the fallbacks in @a fallback
226  */
227 static Eina_List *
228 efreet_dirs_get(const char *key, const char *fallback)
229 {
230     Eina_List *dirs = NULL;
231     const char *path;
232     char *tmp, *s, *p;
233     char ts[PATH_MAX];
234     size_t len;
235
236     path = getenv(key);
237     if (!path || (path[0] == '\0')) path = fallback;
238
239     if (!path) return dirs;
240
241     len = strlen(path) + 1;
242     tmp = alloca(len);
243     memcpy(tmp, path, len);
244     s = tmp;
245     p = strchr(s, EFREET_PATH_SEP);
246     while (p)
247     {
248         *p = '\0';
249         if (!eina_list_search_unsorted(dirs, EINA_COMPARE_CB(strcmp), s))
250         {
251             // resolve path properly/fully to remove path//path2 to
252             // path/path2, path/./path2 to path/path2 etc.
253             if (realpath(s, ts))
254                 dirs = eina_list_append(dirs, (void *)eina_stringshare_add(ts));
255         }
256
257         s = ++p;
258         p = strchr(s, EFREET_PATH_SEP);
259     }
260     if (!eina_list_search_unsorted(dirs, EINA_COMPARE_CB(strcmp), s))
261     {
262         // resolve path properly/fully to remove path//path2 to
263         // path/path2, path/./path2 to path/path2 etc.
264         if (realpath(s, ts))
265             dirs = eina_list_append(dirs, (void *)eina_stringshare_add(ts));
266     }
267
268     return dirs;
269 }
270
271 static const char *
272 efreet_env_expand(const char *in)
273 {
274    Eina_Strbuf *sb;
275    const char *ret, *p, *e1 = NULL, *e2 = NULL, *val;
276    char *env;
277
278    if (!in) return NULL;
279    sb = eina_strbuf_new();
280    if (!sb) return NULL;
281    
282    /* maximum length of any env var is the input string */
283    env = alloca(strlen(in) + 1);
284    for (p = in; *p; p++)
285      {
286         if (!e1)
287           {
288              if (*p == '$') e1 = p + 1;
289              else eina_strbuf_append_char(sb, *p);
290           }
291         else if (!(((*p >= 'a') && (*p <= 'z')) ||
292                    ((*p >= 'A') && (*p <= 'Z')) ||
293                    ((*p >= '0') && (*p <= '9')) ||
294                    (*p == '_')))
295           {
296              size_t len;
297              
298              e2 = p;
299              len = (size_t)(e2 - e1);
300              if (len > 0)
301                {
302                   memcpy(env, e1, len);
303                   env[len] = 0;
304                   val = getenv(env);
305                   if (val) eina_strbuf_append(sb, val);
306                }
307              e1 = NULL;
308              eina_strbuf_append_char(sb, *p);
309           }
310      }
311    ret = eina_stringshare_add(eina_strbuf_string_get(sb));
312    eina_strbuf_free(sb);
313    return ret;
314 }
315
316 /**
317  * @internal
318  * @param key The user-dirs key to lookup
319  * @param fallback The fallback value to use
320  * @return Returns the directory related to the given key or the fallback
321  * @brief This tries to determine the correct directory name given the
322  * user-dirs key @a key and fallbacks @a fallback.
323  */
324 static const char *
325 efreet_user_dir_get(const char *key, const char *fallback)
326 {
327    Eina_File *file = NULL;
328    Eina_File_Line *line;
329    Eina_Iterator *it = NULL;
330    const char *config_home;
331    char path[PATH_MAX];
332    char *ret = NULL;
333
334    config_home = efreet_config_home_get();
335    snprintf(path, sizeof(path), "%s/user-dirs.dirs", config_home);
336
337    file = eina_file_open(path, EINA_FALSE);
338    if (!file) goto fallback;
339    it = eina_file_map_lines(file);
340    if (!it) goto fallback;
341    EINA_ITERATOR_FOREACH(it, line)
342      {
343         const char *eq, *end;
344         Eina_Bool quote = EINA_FALSE;
345
346         if (line->length < 3) continue;
347         if (line->start[0] == '#') continue;
348         if (strncmp(line->start, "XDG", 3)) continue;
349         eq = memchr(line->start, '=', line->length);
350         if (!eq) continue;
351         if (strncmp(key, line->start, eq - line->start)) continue;
352         if (++eq >= line->end) continue;
353         if (*eq == '"')
354         {
355             quote = EINA_TRUE;
356             if (++eq >= line->end) continue;
357         }
358         if (quote)
359             end = memchr(eq, '"', line->end - eq);
360         else
361         {
362             end = line->end;
363             while (isspace(*end)) end--;
364         }
365         if (!end) continue;
366         ret = alloca(end - eq + 1);
367         memcpy(ret, eq, end - eq);
368         ret[end - eq] = '\0';
369         break;
370      }
371 fallback:
372    if (it) eina_iterator_free(it);
373    if (file) eina_file_close(file);
374    if (!ret)
375      {
376         const char *home;
377         home = efreet_home_dir_get();
378         ret = alloca(strlen(home) + strlen(fallback) + 2);
379         sprintf(ret, "%s/%s", home, fallback);
380      }
381    return efreet_env_expand(ret);
382 }