EFL 1.7 svn doobies
[profile/ivi/efreet.git] / src / lib / efreet_utils.c
1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4
5 /* TODO: add no_display check, as we might want only displayable items */
6
7 #undef alloca
8 #ifdef HAVE_ALLOCA_H
9 # include <alloca.h>
10 #elif defined __GNUC__
11 # define alloca __builtin_alloca
12 #elif defined _AIX
13 # define alloca __alloca
14 #elif defined _MSC_VER
15 # include <malloc.h>
16 # define alloca _alloca
17 #else
18 # include <stddef.h>
19 # ifdef  __cplusplus
20 extern "C"
21 # endif
22 void *alloca (size_t);
23 #endif
24
25 #include <fnmatch.h>
26
27 #include <Ecore_File.h>
28
29 /* define macros and variable for using the eina logging system  */
30 #define EFREET_MODULE_LOG_DOM _efreet_utils_log_dom
31 static int _efreet_utils_log_dom = -1;
32
33 #include "Efreet.h"
34 #include "efreet_private.h"
35
36 static char *efreet_util_path_in_default(const char *section, const char *path);
37
38 static int  efreet_util_glob_match(const char *str, const char *glob);
39
40 static Eina_List *efreet_util_menus_find_helper(Eina_List *menus, const char *config_dir);
41
42 static Efreet_Desktop *efreet_util_cache_find(const char *search, const char *what1, const char *what2);
43 static Eina_List *efreet_util_cache_list(const char *search, const char *what);
44 static Eina_List *efreet_util_cache_glob_list(const char *search, const char *what);
45
46 static Eina_Hash *file_id_by_desktop_path = NULL;
47
48 static int init = 0;
49
50 int
51 efreet_util_init(void)
52 {
53     if (init++) return init;
54     _efreet_utils_log_dom = eina_log_domain_register
55       ("efreet_util", EFREET_DEFAULT_LOG_COLOR);
56     if (_efreet_utils_log_dom < 0)
57     {
58         EINA_LOG_ERR("Efreet: Could not create a log domain for efreet_util");
59         return 0;
60     }
61
62     file_id_by_desktop_path = eina_hash_string_superfast_new(EINA_FREE_CB(eina_stringshare_del));
63
64     return init;
65 }
66
67 int
68 efreet_util_shutdown(void)
69 {
70     if (--init) return init;
71
72     eina_log_domain_unregister(_efreet_utils_log_dom);
73     _efreet_utils_log_dom = -1;
74     IF_FREE_HASH(file_id_by_desktop_path);
75
76     return init;
77 }
78
79 static char *
80 efreet_util_path_in_default(const char *section, const char *path)
81 {
82     Eina_List *dirs;
83     char *ret = NULL;
84     char *dir;
85
86     dirs = efreet_default_dirs_get(efreet_data_home_get(), efreet_data_dirs_get(),
87                                    section);
88
89     EINA_LIST_FREE(dirs, dir)
90     {
91         if (!strncmp(path, dir, strlen(dir)))
92             ret = dir;
93         else
94             eina_stringshare_del(dir);
95     }
96
97     return ret;
98 }
99
100 EAPI const char *
101 efreet_util_path_to_file_id(const char *path)
102 {
103     size_t len, len2;
104     char *tmp, *p;
105     char *base;
106     const char *file_id;
107
108     EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL);
109
110     file_id = eina_hash_find(file_id_by_desktop_path, path);
111     if (file_id) return file_id;
112
113     base = efreet_util_path_in_default("applications", path);
114     if (!base) return NULL;
115
116     len = strlen(base);
117     if (strlen(path) <= len)
118     {
119         eina_stringshare_del(base);
120         return NULL;
121     }
122     if (strncmp(path, base, len))
123     {
124         eina_stringshare_del(base);
125         return NULL;
126     }
127
128     len2 = strlen(path + len + 1) + 1;
129     tmp = alloca(len2);
130     memcpy(tmp, path + len + 1, len2);
131     p = tmp;
132     while (*p)
133     {
134         if (*p == '/') *p = '-';
135         p++;
136     }
137     eina_stringshare_del(base);
138     file_id = eina_stringshare_add(tmp);
139     eina_hash_add(file_id_by_desktop_path, path, (void *)file_id);
140     return file_id;
141 }
142
143 EAPI Eina_List *
144 efreet_util_desktop_mime_list(const char *mime)
145 {
146     EINA_SAFETY_ON_NULL_RETURN_VAL(mime, NULL);
147     return efreet_util_cache_list("mime_types", mime);
148 }
149
150 EAPI Efreet_Desktop *
151 efreet_util_desktop_wm_class_find(const char *wmname, const char *wmclass)
152 {
153     EINA_SAFETY_ON_TRUE_RETURN_VAL((!wmname) && (!wmclass), NULL);
154     return efreet_util_cache_find("startup_wm_class", wmname, wmclass);
155 }
156
157 EAPI Efreet_Desktop *
158 efreet_util_desktop_file_id_find(const char *file_id)
159 {
160     Efreet_Cache_Hash *hash;
161     Efreet_Desktop *ret = NULL;
162     const char *str;
163
164     EINA_SAFETY_ON_NULL_RETURN_VAL(file_id, NULL);
165
166     hash = efreet_cache_util_hash_string("file_id");
167     if (!hash) return NULL;
168     str = eina_hash_find(hash->hash, file_id);
169     if (str)
170         ret = efreet_desktop_get(str);
171     return ret;
172 }
173
174 EAPI Efreet_Desktop *
175 efreet_util_desktop_exec_find(const char *exec)
176 {
177     Efreet_Cache_Hash *hash = NULL;
178     Efreet_Desktop *ret = NULL;
179     Efreet_Cache_Array_String *names = NULL;
180     unsigned int i;
181
182     EINA_SAFETY_ON_NULL_RETURN_VAL(exec, NULL);
183
184     names = efreet_cache_util_names("exec_list");
185     if (!names) return NULL;
186     for (i = 0; i < names->array_count; i++)
187     {
188         const char *file;
189         char *exe;
190         unsigned int j;
191         Efreet_Cache_Array_String *array;
192
193         exe = ecore_file_app_exe_get(names->array[i]);
194         if (!exe) continue;
195         file = ecore_file_file_get(exe);
196         if (!file) continue;
197         if (strcmp(exec, exe) && strcmp(exec, file))
198         {
199             free(exe);
200             continue;
201         }
202         free(exe);
203
204         if (!hash)
205             hash = efreet_cache_util_hash_array_string("exec_hash");
206         if (!hash) return NULL;
207         array = eina_hash_find(hash->hash, names->array[i]);
208         if (!array) continue;
209         for (j = 0; j < array->array_count; j++)
210         {
211             ret = efreet_desktop_get(array->array[j]);
212             if (ret) break;
213         }
214         if (ret) break;
215     }
216     return ret;
217 }
218
219 EAPI Efreet_Desktop *
220 efreet_util_desktop_name_find(const char *name)
221 {
222     EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL);
223     return efreet_util_cache_find("name", name, NULL);
224 }
225
226 EAPI Efreet_Desktop *
227 efreet_util_desktop_generic_name_find(const char *generic_name)
228 {
229     EINA_SAFETY_ON_NULL_RETURN_VAL(generic_name, NULL);
230     return efreet_util_cache_find("generic_name", generic_name, NULL);
231 }
232
233 EAPI Eina_List *
234 efreet_util_desktop_name_glob_list(const char *glob)
235 {
236     EINA_SAFETY_ON_NULL_RETURN_VAL(glob, NULL);
237     return efreet_util_cache_glob_list("name", glob);
238 }
239
240 EAPI Eina_List *
241 efreet_util_desktop_exec_glob_list(const char *glob)
242 {
243     Efreet_Cache_Hash *hash = NULL;
244     Eina_List *ret = NULL;
245     Efreet_Cache_Array_String *names = NULL;
246     unsigned int i;
247
248     EINA_SAFETY_ON_NULL_RETURN_VAL(glob, NULL);
249
250     if (!strcmp(glob, "*"))
251         glob = NULL;
252
253     names = efreet_cache_util_names("exec_list");
254     if (!names) return NULL;
255     for (i = 0; i < names->array_count; i++)
256     {
257         Efreet_Cache_Array_String *array;
258         unsigned int j;
259         char *exe;
260         Efreet_Desktop *desk;
261
262         exe = ecore_file_app_exe_get(names->array[i]);
263         if (!exe) continue;
264         if (glob && !efreet_util_glob_match(exe, glob))
265         {
266             free(exe);
267             continue;
268         }
269         free(exe);
270
271         if (!hash)
272             hash = efreet_cache_util_hash_array_string("exec_hash");
273         if (!hash) return NULL;
274
275         array = eina_hash_find(hash->hash, names->array[i]);
276         if (!array) continue;
277         for (j = 0; j < array->array_count; j++)
278         {
279             desk = efreet_desktop_get(array->array[j]);
280             if (desk)
281                 ret = eina_list_append(ret, desk);
282         }
283     }
284     return ret;
285 }
286
287 EAPI Eina_List *
288 efreet_util_desktop_generic_name_glob_list(const char *glob)
289 {
290     EINA_SAFETY_ON_NULL_RETURN_VAL(glob, NULL);
291     return efreet_util_cache_glob_list("generic_name", glob);
292 }
293
294 EAPI Eina_List *
295 efreet_util_desktop_comment_glob_list(const char *glob)
296 {
297     EINA_SAFETY_ON_NULL_RETURN_VAL(glob, NULL);
298     return efreet_util_cache_glob_list("comment", glob);
299 }
300
301 EAPI Eina_List *
302 efreet_util_desktop_categories_list(void)
303 {
304     Efreet_Cache_Array_String *array;
305     Eina_List *ret = NULL;
306     unsigned int i;
307
308     array = efreet_cache_util_names("categories_list");
309     if (!array) return NULL;
310     for (i = 0; i < array->array_count; i++)
311         ret = eina_list_append(ret, array->array[i]);
312     return ret;
313 }
314
315 EAPI Eina_List *
316 efreet_util_desktop_category_list(const char *category)
317 {
318     EINA_SAFETY_ON_NULL_RETURN_VAL(category, NULL);
319     return efreet_util_cache_list("categories", category);
320 }
321
322 static int
323 efreet_util_glob_match(const char *str, const char *glob)
324 {
325     if (!str || !glob)
326         return 0;
327     if (glob[0] == '\0')
328     {
329         if (str[0] == '\0') return 1;
330         return 0;
331     }
332     if (!strcmp(glob, "*")) return 1;
333     if (!fnmatch(glob, str, 0)) return 1;
334     return 0;
335 }
336
337 EAPI Eina_List *
338 efreet_util_menus_find(void)
339 {
340     Eina_List *menus = NULL;
341     Eina_List *dirs, *l;
342     const char *dir;
343
344     menus = efreet_util_menus_find_helper(menus, efreet_config_home_get());
345
346     dirs = efreet_config_dirs_get();
347     EINA_LIST_FOREACH(dirs, l, dir)
348         menus = efreet_util_menus_find_helper(menus, dir);
349
350     return menus;
351 }
352
353 static Eina_List *
354 efreet_util_menus_find_helper(Eina_List *menus, const char *config_dir)
355 {
356     Eina_Iterator *it;
357     Eina_File_Direct_Info *info;
358     char dbuf[PATH_MAX];
359
360     snprintf(dbuf, sizeof(dbuf), "%s/menus", config_dir);
361     it = eina_file_direct_ls(dbuf);
362     if (!it) return menus;
363     EINA_ITERATOR_FOREACH(it, info)
364     {
365         const char *exten;
366         exten = strrchr(info->path + info->name_start, '.');
367         if (!exten) continue;
368         if (strcmp(".menu", exten)) continue;
369
370         if (ecore_file_is_dir(info->path)) continue;
371
372         menus = eina_list_append(menus, strdup(info->path));
373     }
374     eina_iterator_free(it);
375     return menus;
376 }
377
378 static Efreet_Desktop *
379 efreet_util_cache_find(const char *search, const char *what1, const char *what2)
380 {
381     Efreet_Cache_Hash *hash;
382     Efreet_Desktop *ret = NULL;
383     Efreet_Cache_Array_String *array = NULL;
384     char key[256];
385
386     if ((!what1) && (!what2)) return NULL;
387
388     snprintf(key, sizeof(key), "%s_hash", search);
389     hash = efreet_cache_util_hash_array_string(key);
390     if (!hash) return NULL;
391     if (what1)
392         array = eina_hash_find(hash->hash, what1);
393     if (!array && what2) array = eina_hash_find(hash->hash, what2);
394     if (array)
395     {
396         unsigned int i;
397
398         for (i = 0; i < array->array_count; i++)
399         {
400             ret = efreet_desktop_get(array->array[i]);
401             if (ret) break;
402         }
403     }
404     return ret;
405 }
406
407 static Eina_List *
408 efreet_util_cache_list(const char *search, const char *what)
409 {
410     Efreet_Cache_Hash *hash;
411     Efreet_Cache_Array_String *array;
412     Eina_List *ret = NULL;
413     char key[256];
414
415     if (!what) return NULL;
416
417     snprintf(key, sizeof(key), "%s_hash", search);
418     hash = efreet_cache_util_hash_array_string(key);
419     if (!hash) return NULL;
420     array = eina_hash_find(hash->hash, what);
421     if (array)
422     {
423         unsigned int i;
424         Efreet_Desktop *desk;
425
426         for (i = 0; i < array->array_count; i++)
427         {
428             desk = efreet_desktop_get(array->array[i]);
429             if (desk)
430                 ret = eina_list_append(ret, desk);
431         }
432     }
433     return ret;
434 }
435
436 static Eina_List *
437 efreet_util_cache_glob_list(const char *search, const char *what)
438 {
439     Efreet_Cache_Hash *hash = NULL;
440     Eina_List *ret = NULL;
441     Efreet_Cache_Array_String *names = NULL;
442     char key[256];
443     unsigned int i;
444
445     if (!what) return NULL;
446     if (!strcmp(what, "*"))
447         what = NULL;
448
449     snprintf(key, sizeof(key), "%s_list", search);
450     names = efreet_cache_util_names(key);
451     if (!names) return NULL;
452     for (i = 0; i < names->array_count; i++)
453     {
454         Efreet_Cache_Array_String *array;
455         unsigned int j;
456         Efreet_Desktop *desk;
457
458         if (what && !efreet_util_glob_match(names->array[i], what)) continue;
459
460         if (!hash)
461         {
462             snprintf(key, sizeof(key), "%s_hash", search);
463             hash = efreet_cache_util_hash_array_string(key);
464         }
465         if (!hash) return NULL;
466
467         array = eina_hash_find(hash->hash, names->array[i]);
468         if (!array) continue;
469         for (j = 0; j < array->array_count; j++)
470         {
471             desk = efreet_desktop_get(array->array[j]);
472             if (desk)
473                 ret = eina_list_append(ret, desk);
474         }
475     }
476     return ret;
477 }
478
479 /*
480  * Needs EAPI because of helper binaries
481  */
482 EAPI void
483 efreet_hash_free(Eina_Hash *hash, Eina_Free_Cb free_cb)
484 {
485     eina_hash_free_cb_set(hash, free_cb);
486     eina_hash_free(hash);
487 }
488