1 #include "e.h"
2 
3 /* local subsystem functions */
4 static void      _e_path_free(E_Path *ep);
5 static void      _e_path_cache_free(E_Path *ep);
6 static Eina_Bool _e_path_cache_free_cb(const Eina_Hash *hash, const void *key, void *data, void *fdata);
7 
8 /* externally accessible functions */
9 E_API E_Path *
e_path_new(void)10 e_path_new(void)
11 {
12    E_Path *ep;
13 
14    ep = E_OBJECT_ALLOC(E_Path, E_PATH_TYPE, _e_path_free);
15    return ep;
16 }
17 
18 E_API void
e_path_default_path_append(E_Path * ep,const char * path)19 e_path_default_path_append(E_Path *ep, const char *path)
20 {
21    E_OBJECT_CHECK(ep);
22    E_OBJECT_TYPE_CHECK(ep, E_PATH_TYPE);
23    if (!path) return;
24    if (path[0] == '~')
25      {
26         E_Path_Dir *epd;
27         char *new_path;
28         const char *home_dir;
29         int len1, len2;
30 
31         home_dir = e_user_homedir_get();
32         len1 = strlen(home_dir);
33         len2 = strlen(path);
34         new_path = malloc(len1 + len2 + 1);
35         if (!new_path) return;
36         epd = malloc(sizeof(E_Path_Dir));
37         if (!epd)
38           {
39              free(new_path);
40              return;
41           }
42 
43         strcpy(new_path, home_dir);
44         strcat(new_path, path + 1);
45         epd->dir = eina_stringshare_add(new_path);
46         free(new_path);
47         ep->default_dir_list = eina_list_append(ep->default_dir_list, epd);
48      }
49    else
50      {
51         E_Path_Dir *epd;
52         epd = malloc(sizeof(E_Path_Dir));
53         if (!epd)
54           return;
55         epd->dir = eina_stringshare_add(path);
56         ep->default_dir_list = eina_list_append(ep->default_dir_list, epd);
57      }
58    _e_path_cache_free(ep);
59 }
60 
61 E_API void
e_path_user_path_set(E_Path * ep,Eina_List ** user_dir_list)62 e_path_user_path_set(E_Path *ep, Eina_List **user_dir_list)
63 {
64    E_OBJECT_CHECK(ep);
65    E_OBJECT_TYPE_CHECK(ep, E_PATH_TYPE);
66 
67    ep->user_dir_list = user_dir_list;
68    _e_path_cache_free(ep);
69 }
70 
71 E_API void
e_path_user_path_append(E_Path * ep,const char * path)72 e_path_user_path_append(E_Path *ep, const char *path)
73 {
74    E_OBJECT_CHECK(ep);
75    E_OBJECT_TYPE_CHECK(ep, E_PATH_TYPE);
76    if (!path) return;
77    if (path[0] == '~')
78      {
79         E_Path_Dir *epd;
80         char *new_path;
81         const char *home_dir;
82         int len1, len2;
83 
84         home_dir = e_user_homedir_get();
85         len1 = strlen(home_dir);
86         len2 = strlen(path);
87         new_path = malloc(len1 + len2 + 1);
88         if (!new_path) return;
89         epd = malloc(sizeof(E_Path_Dir));
90         if (!epd)
91           {
92              free(new_path);
93              return;
94           }
95 
96         strcpy(new_path, home_dir);
97         strcat(new_path, path + 1);
98         epd->dir = eina_stringshare_add(new_path);
99         free(new_path);
100         *(ep->user_dir_list) = eina_list_append(*(ep->user_dir_list), epd);
101      }
102    else
103      {
104         E_Path_Dir *epd;
105         epd = malloc(sizeof(E_Path_Dir));
106         if (!epd)
107           return;
108         epd->dir = eina_stringshare_add(path);
109         *(ep->user_dir_list) = eina_list_append(*(ep->user_dir_list), epd);
110      }
111    _e_path_cache_free(ep);
112 }
113 
114 E_API void
e_path_user_path_prepend(E_Path * ep,const char * path)115 e_path_user_path_prepend(E_Path *ep, const char *path)
116 {
117    E_OBJECT_CHECK(ep);
118    E_OBJECT_TYPE_CHECK(ep, E_PATH_TYPE);
119    if (!path) return;
120    if (path[0] == '~')
121      {
122         E_Path_Dir *epd;
123         char *new_path;
124         const char *home_dir;
125         int len1, len2;
126 
127         home_dir = e_user_homedir_get();
128         len1 = strlen(home_dir);
129         len2 = strlen(path);
130         new_path = malloc(len1 + len2 + 1);
131         if (!new_path) return;
132         epd = malloc(sizeof(E_Path_Dir));
133         if (!epd)
134           {
135              free(new_path);
136              return;
137           }
138 
139         strcpy(new_path, home_dir);
140         strcat(new_path, path + 1);
141         epd->dir = eina_stringshare_add(new_path);
142         free(new_path);
143         *(ep->user_dir_list) = eina_list_prepend(*(ep->user_dir_list), epd);
144      }
145    else
146      {
147         E_Path_Dir *epd;
148         epd = malloc(sizeof(E_Path_Dir));
149         if (!epd)
150           return;
151         epd->dir = eina_stringshare_add(path);
152         *(ep->user_dir_list) = eina_list_prepend(*(ep->user_dir_list), epd);
153      }
154    _e_path_cache_free(ep);
155 }
156 
157 E_API void
e_path_user_path_remove(E_Path * ep,const char * path)158 e_path_user_path_remove(E_Path *ep, const char *path)
159 {
160    Eina_List *l;
161    E_Path_Dir *epd;
162 
163    E_OBJECT_CHECK(ep);
164    E_OBJECT_TYPE_CHECK(ep, E_PATH_TYPE);
165    if (!path) return;
166    if (path[0] == '~')
167      {
168         char *new_path;
169         const char *home_dir;
170         int len1, len2;
171 
172         home_dir = e_user_homedir_get();
173         len1 = strlen(home_dir);
174         len2 = strlen(path);
175         new_path = malloc(len1 + len2 + 1);
176         if (!new_path) return;
177         strcpy(new_path, home_dir);
178         strcat(new_path, path + 1);
179         EINA_LIST_FOREACH(*(ep->user_dir_list), l, epd)
180           {
181              if (epd->dir)
182                {
183                   if (!strcmp(epd->dir, new_path))
184                     {
185                        *(ep->user_dir_list) = eina_list_remove_list(
186                            *(ep->user_dir_list), l);
187                        eina_stringshare_del(epd->dir);
188                        free(epd);
189                        free(new_path);
190                        _e_path_cache_free(ep);
191                        return;
192                     }
193                }
194           }
195         free(new_path);
196      }
197    else
198      {
199         EINA_LIST_FOREACH(*(ep->user_dir_list), l, epd)
200           {
201              if (epd->dir)
202                {
203                   if (!strcmp(epd->dir, path))
204                     {
205                        *(ep->user_dir_list) = eina_list_remove_list(
206                            *(ep->user_dir_list), l);
207                        eina_stringshare_del(epd->dir);
208                        free(epd);
209                        _e_path_cache_free(ep);
210                        return;
211                     }
212                }
213           }
214      }
215 }
216 
217 E_API void
e_path_user_path_clear(E_Path * ep)218 e_path_user_path_clear(E_Path *ep)
219 {
220    E_Path_Dir *epd;
221    EINA_LIST_FREE(*(ep->user_dir_list), epd)
222      {
223         eina_stringshare_del(epd->dir);
224         free(epd);
225      }
226    _e_path_cache_free(ep);
227 }
228 
229 E_API Eina_Stringshare *
e_path_find(E_Path * ep,const char * file)230 e_path_find(E_Path *ep, const char *file)
231 {
232    Eina_List *l;
233    E_Path_Dir *epd;
234    char *str;
235    Eina_Stringshare *ret;
236    char buf[PATH_MAX] = "";
237 
238    E_OBJECT_CHECK_RETURN(ep, NULL);
239    E_OBJECT_TYPE_CHECK_RETURN(ep, E_PATH_TYPE, NULL);
240 
241    if (!file) return NULL;
242    str = eina_hash_find(ep->hash, file);
243    if (str) return eina_stringshare_ref(str);
244    /* Look in the default dir list */
245    EINA_LIST_FOREACH(ep->default_dir_list, l, epd)
246      {
247         if (epd->dir)
248           {
249              snprintf(buf, sizeof(buf), "%s/%s", epd->dir, file);
250              if (ecore_file_exists(buf))
251                {
252                   if (!ep->hash)
253                     ep->hash = eina_hash_string_superfast_new(NULL);
254                   if (eina_hash_population(ep->hash) >= 512)
255                     _e_path_cache_free(ep);
256                   ret = eina_stringshare_add(buf);
257                   eina_hash_add(ep->hash, file, ret);
258                   return eina_stringshare_ref(ret);
259                }
260           }
261      }
262    /* Look in the users dir list */
263    EINA_LIST_FOREACH(*(ep->user_dir_list), l, epd)
264      {
265         if (epd->dir)
266           {
267              snprintf(buf, sizeof(buf), "%s/%s", epd->dir, file);
268              if (ecore_file_exists(buf))
269                {
270                   if (!ep->hash)
271                     ep->hash = eina_hash_string_superfast_new(NULL);
272                   if (eina_hash_population(ep->hash) >= 512)
273                     _e_path_cache_free(ep);
274                   ret = eina_stringshare_add(buf);
275                   eina_hash_add(ep->hash, file, ret);
276                   return eina_stringshare_ref(ret);
277                }
278           }
279      }
280    return NULL;
281 }
282 
283 E_API void
e_path_evas_append(E_Path * ep,Evas * evas)284 e_path_evas_append(E_Path *ep, Evas *evas)
285 {
286    Eina_List *dir_list;
287    E_Path_Dir *epd;
288 
289    E_OBJECT_CHECK(ep);
290    E_OBJECT_TYPE_CHECK(ep, E_PATH_TYPE);
291    if (!evas) return;
292 
293    dir_list = e_path_dir_list_get(ep);
294 
295    EINA_LIST_FREE(dir_list, epd)
296      {
297         if (epd->dir) evas_font_path_append(evas, epd->dir);
298         eina_stringshare_del(epd->dir);
299         free(epd);
300      }
301 }
302 
303 /* combine default_list and and user_list in and easy to use list */
304 E_API Eina_List *
e_path_dir_list_get(E_Path * ep)305 e_path_dir_list_get(E_Path *ep)
306 {
307    Eina_List *dir_list;
308    Eina_List *l;
309    E_Path_Dir *new_epd;
310    E_Path_Dir *epd;
311 
312    dir_list = NULL;
313 
314    if (ep->user_dir_list)
315      {
316         EINA_LIST_FOREACH(*(ep->user_dir_list), l, epd)
317           {
318              new_epd = malloc(sizeof(E_Path_Dir));
319              new_epd->dir = eina_stringshare_add(epd->dir);
320              dir_list = eina_list_append(dir_list, new_epd);
321           }
322      }
323 
324    EINA_LIST_FOREACH(ep->default_dir_list, l, epd)
325      {
326         new_epd = malloc(sizeof(E_Path_Dir));
327         new_epd->dir = eina_stringshare_add(epd->dir);
328         dir_list = eina_list_append(dir_list, new_epd);
329      }
330 
331    return dir_list;
332 }
333 
334 E_API void
e_path_dir_list_free(Eina_List * dir_list)335 e_path_dir_list_free(Eina_List *dir_list)
336 {
337    E_Path_Dir *epd;
338 
339    EINA_LIST_FREE(dir_list, epd)
340      {
341         eina_stringshare_del(epd->dir);
342         free(epd);
343      }
344 }
345 
346 /* local subsystem functions */
347 static void
_e_path_free(E_Path * ep)348 _e_path_free(E_Path *ep)
349 {
350    E_Path_Dir *epd;
351 
352    _e_path_cache_free(ep);
353    EINA_LIST_FREE(ep->default_dir_list, epd)
354      {
355         eina_stringshare_del(epd->dir);
356         free(epd);
357      }
358    free(ep);
359 }
360 
361 static void
_e_path_cache_free(E_Path * ep)362 _e_path_cache_free(E_Path *ep)
363 {
364    if (!ep->hash) return;
365    eina_hash_foreach(ep->hash, _e_path_cache_free_cb, NULL);
366    eina_hash_free(ep->hash);
367    ep->hash = NULL;
368 }
369 
370 static Eina_Bool
_e_path_cache_free_cb(const Eina_Hash * hash EINA_UNUSED,const void * key EINA_UNUSED,void * data,void * fdata EINA_UNUSED)371 _e_path_cache_free_cb(const Eina_Hash *hash EINA_UNUSED, const void *key EINA_UNUSED, void *data, void *fdata EINA_UNUSED)
372 {
373    eina_stringshare_del(data);
374    return 1;
375 }
376 
377