efl/legacy/efreet/src/lib/efreet_base.c

479 lines
13 KiB
C
Raw Normal View History

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#undef alloca
#ifdef HAVE_ALLOCA_H
# include <alloca.h>
#elif defined __GNUC__
# define alloca __builtin_alloca
#elif defined _AIX
# define alloca __alloca
#elif defined _MSC_VER
# include <malloc.h>
# define alloca _alloca
#else
# include <stddef.h>
# ifdef __cplusplus
extern "C"
# endif
void *alloca (size_t);
#endif
#include <unistd.h>
#ifdef _WIN32
# include <winsock2.h>
#endif
/* define macros and variable for using the eina logging system */
#define EFREET_MODULE_LOG_DOM _efreet_base_log_dom
static int _efreet_base_log_dom = -1;
#include "Efreet.h"
#include "efreet_private.h"
2010-05-29 01:30:06 -07:00
static Efreet_Version _version = { VMAJ, VMIN, VMIC, VREV };
EAPI Efreet_Version *efreet_version = &_version;
#ifdef _WIN32
# define EFREET_PATH_SEP ';'
#else
# define EFREET_PATH_SEP ':'
#endif
static const char *efreet_home_dir = NULL;
static const char *xdg_data_home = NULL;
static const char *xdg_config_home = NULL;
static const char *xdg_cache_home = NULL;
static const char *xdg_runtime_dir = NULL;
static Eina_List *xdg_data_dirs = NULL;
static Eina_List *xdg_config_dirs = NULL;
static const char *xdg_desktop_dir = NULL;
static const char *xdg_download_dir = NULL;
static const char *xdg_templates_dir = NULL;
static const char *xdg_publicshare_dir = NULL;
static const char *xdg_documents_dir = NULL;
static const char *xdg_music_dir = NULL;
static const char *xdg_pictures_dir = NULL;
static const char *xdg_videos_dir = NULL;
static const char *hostname = NULL;
static const char *efreet_dir_get(const char *key, const char *fallback);
static Eina_List *efreet_dirs_get(const char *key,
const char *fallback);
static const char *efreet_user_dir_get(const char *key, const char *fallback);
/**
* @internal
* @return Returns @c 1 on success or @c 0 on failure
* @brief Initializes the efreet base settings
*/
int
efreet_base_init(void)
{
_efreet_base_log_dom = eina_log_domain_register
("efreet_base", EFREET_DEFAULT_LOG_COLOR);
if (_efreet_base_log_dom < 0)
{
EINA_LOG_ERR("Efreet: Could not create a log domain for efreet_base.\n");
2010-02-04 01:12:35 -08:00
return 0;
}
return 1;
}
/**
* @internal
* @return Returns no value
* @brief Cleans up the efreet base settings system
*/
void
efreet_base_shutdown(void)
{
IF_RELEASE(efreet_home_dir);
IF_RELEASE(xdg_desktop_dir);
IF_RELEASE(xdg_download_dir);
IF_RELEASE(xdg_templates_dir);
IF_RELEASE(xdg_publicshare_dir);
IF_RELEASE(xdg_documents_dir);
IF_RELEASE(xdg_music_dir);
IF_RELEASE(xdg_pictures_dir);
IF_RELEASE(xdg_videos_dir);
IF_RELEASE(xdg_data_home);
IF_RELEASE(xdg_config_home);
IF_RELEASE(xdg_cache_home);
IF_RELEASE(xdg_runtime_dir);
2009-03-23 05:19:31 -07:00
IF_FREE_LIST(xdg_data_dirs, eina_stringshare_del);
IF_FREE_LIST(xdg_config_dirs, eina_stringshare_del);
IF_RELEASE(hostname);
eina_log_domain_unregister(_efreet_base_log_dom);
_efreet_base_log_dom = -1;
}
/**
* @internal
* @return Returns the users home directory
* @brief Gets the users home directory and returns it.
*/
const char *
efreet_home_dir_get(void)
{
if (efreet_home_dir) return efreet_home_dir;
efreet_home_dir = getenv("HOME");
#ifdef _WIN32
if (!efreet_home_dir || efreet_home_dir[0] == '\0')
efreet_home_dir = getenv("USERPROFILE");
#endif
if (!efreet_home_dir || efreet_home_dir[0] == '\0')
efreet_home_dir = "/tmp";
efreet_home_dir = eina_stringshare_add(efreet_home_dir);
return efreet_home_dir;
}
EAPI const char *
efreet_desktop_dir_get(void)
{
if (xdg_desktop_dir) return xdg_desktop_dir;
xdg_desktop_dir = efreet_user_dir_get("XDG_DESKTOP_DIR", _("Desktop"));
return xdg_desktop_dir;
}
EAPI const char *
efreet_download_dir_get(void)
{
if (xdg_download_dir) return xdg_download_dir;
xdg_download_dir = efreet_user_dir_get("XDG_DOWNLOAD_DIR", _("Downloads"));
return xdg_download_dir;
}
EAPI const char *
efreet_templates_dir_get(void)
{
if (xdg_templates_dir) return xdg_templates_dir;
xdg_templates_dir = efreet_user_dir_get("XDG_TEMPLATES_DIR",
_("Templates"));
return xdg_templates_dir;
}
EAPI const char *
efreet_public_share_dir_get(void)
{
if (xdg_publicshare_dir) return xdg_publicshare_dir;
xdg_publicshare_dir = efreet_user_dir_get("XDG_PUBLICSHARE_DIR",
_("Public"));
return xdg_publicshare_dir;
}
EAPI const char *
efreet_documents_dir_get(void)
{
if (xdg_documents_dir) return xdg_documents_dir;
xdg_documents_dir = efreet_user_dir_get("XDG_DOCUMENTS_DIR",
_("Documents"));
return xdg_documents_dir;
}
EAPI const char *
efreet_music_dir_get(void)
{
if (xdg_music_dir) return xdg_music_dir;
xdg_music_dir = efreet_user_dir_get("XDG_MUSIC_DIR", _("Music"));
return xdg_music_dir;
}
EAPI const char *
efreet_pictures_dir_get(void)
{
if (xdg_pictures_dir) return xdg_pictures_dir;
xdg_pictures_dir = efreet_user_dir_get("XDG_PICTURES_DIR", _("Pictures"));
return xdg_pictures_dir;
}
EAPI const char *
efreet_videos_dir_get(void)
{
if (xdg_videos_dir) return xdg_videos_dir;
xdg_videos_dir = efreet_user_dir_get("XDG_VIDEOS_DIR", _("Videos"));
return xdg_videos_dir;
}
2007-11-04 01:32:35 -08:00
EAPI const char *
efreet_data_home_get(void)
{
if (xdg_data_home) return xdg_data_home;
xdg_data_home = efreet_dir_get("XDG_DATA_HOME", "/.local/share");
return xdg_data_home;
}
EAPI Eina_List *
efreet_data_dirs_get(void)
{
#ifdef _WIN32
char buf[4096];
#endif
if (xdg_data_dirs) return xdg_data_dirs;
#ifdef _WIN32
snprintf(buf, 4096, "%s\\Efl;" PACKAGE_DATA_DIR ";/usr/share;/usr/local/share", getenv("APPDATA"));
xdg_data_dirs = efreet_dirs_get("XDG_DATA_DIRS", buf);
#else
xdg_data_dirs = efreet_dirs_get("XDG_DATA_DIRS",
PACKAGE_DATA_DIR ":/usr/share:/usr/local/share");
#endif
return xdg_data_dirs;
}
2007-11-04 01:32:35 -08:00
EAPI const char *
efreet_config_home_get(void)
{
if (xdg_config_home) return xdg_config_home;
xdg_config_home = efreet_dir_get("XDG_CONFIG_HOME", "/.config");
return xdg_config_home;
}
EAPI Eina_List *
efreet_config_dirs_get(void)
{
if (xdg_config_dirs) return xdg_config_dirs;
xdg_config_dirs = efreet_dirs_get("XDG_CONFIG_DIRS", "/etc/xdg");
return xdg_config_dirs;
}
2007-11-04 01:32:35 -08:00
EAPI const char *
efreet_cache_home_get(void)
{
if (xdg_cache_home) return xdg_cache_home;
xdg_cache_home = efreet_dir_get("XDG_CACHE_HOME", "/.cache");
return xdg_cache_home;
}
EAPI const char *
efreet_runtime_dir_get(void)
{
if (xdg_runtime_dir) return xdg_runtime_dir;
xdg_runtime_dir = efreet_dir_get("XDG_RUNTIME_DIR", "/tmp");
return xdg_runtime_dir;
}
EAPI const char *
efreet_hostname_get(void)
{
char buf[256];
if (hostname) return hostname;
if (gethostname(buf, sizeof(buf)) < 0)
hostname = eina_stringshare_add("");
else
hostname = eina_stringshare_add(buf);
return hostname;
}
void
efreet_dirs_reset(void)
{
eina_stringshare_replace(&xdg_desktop_dir, NULL);
eina_stringshare_replace(&xdg_download_dir, NULL);
eina_stringshare_replace(&xdg_templates_dir, NULL);
eina_stringshare_replace(&xdg_publicshare_dir, NULL);
eina_stringshare_replace(&xdg_documents_dir, NULL);
eina_stringshare_replace(&xdg_music_dir, NULL);
eina_stringshare_replace(&xdg_pictures_dir, NULL);
eina_stringshare_replace(&xdg_videos_dir, NULL);
}
/**
* @internal
* @param key The environment key to lookup
2011-01-27 09:49:45 -08:00
* @param fallback The fallback value to use
* @return Returns the directory related to the given key or the fallback
* @brief This tries to determine the correct directory name given the
* environment key @a key and fallbacks @a fallback.
*/
static const char *
efreet_dir_get(const char *key, const char *fallback)
{
char *dir;
const char *t;
dir = getenv(key);
if (!dir || dir[0] == '\0')
{
int len;
const char *user;
user = efreet_home_dir_get();
len = strlen(user) + strlen(fallback) + 1;
dir = alloca(len);
snprintf(dir, len, "%s%s", user, fallback);
t = eina_stringshare_add(dir);
}
else t = eina_stringshare_add(dir);
return t;
}
/**
* @internal
2011-01-27 09:49:45 -08:00
* @param key The environment key to lookup
* @param fallback The fallback value to use
* @return Returns a list of directories specified by the given key @a key
* or from the list of fallbacks in @a fallback.
* @brief Creates a list of directories as given in the environment key @a
* key or from the fallbacks in @a fallback
*/
static Eina_List *
efreet_dirs_get(const char *key, const char *fallback)
{
Eina_List *dirs = NULL;
const char *path;
char *tmp, *s, *p;
char ts[PATH_MAX];
size_t len;
path = getenv(key);
if (!path || (path[0] == '\0')) path = fallback;
if (!path) return dirs;
len = strlen(path) + 1;
tmp = alloca(len);
memcpy(tmp, path, len);
s = tmp;
p = strchr(s, EFREET_PATH_SEP);
while (p)
{
*p = '\0';
if (!eina_list_search_unsorted(dirs, EINA_COMPARE_CB(strcmp), s))
2010-05-16 12:36:42 -07:00
{
// resolve path properly/fully to remove path//path2 to
// path/path2, path/./path2 to path/path2 etc.
if (realpath(s, ts))
2010-05-16 12:36:42 -07:00
dirs = eina_list_append(dirs, (void *)eina_stringshare_add(ts));
}
s = ++p;
p = strchr(s, EFREET_PATH_SEP);
}
if (!eina_list_search_unsorted(dirs, EINA_COMPARE_CB(strcmp), s))
{
// resolve path properly/fully to remove path//path2 to
// path/path2, path/./path2 to path/path2 etc.
if (realpath(s, ts))
dirs = eina_list_append(dirs, (void *)eina_stringshare_add(ts));
}
return dirs;
}
static const char *
efreet_env_expand(const char *in)
{
Eina_Strbuf *sb;
const char *ret, *p, *e1 = NULL, *e2 = NULL, *val;
char *env;
if (!in) return NULL;
sb = eina_strbuf_new();
if (!sb) return NULL;
/* maximum length of any env var is the input string */
env = alloca(strlen(in) + 1);
for (p = in; *p; p++)
{
if (!e1)
{
if (*p == '$') e1 = p + 1;
else eina_strbuf_append_char(sb, *p);
}
else if (!(((*p >= 'a') && (*p <= 'z')) ||
((*p >= 'A') && (*p <= 'Z')) ||
((*p >= '0') && (*p <= '9')) ||
(*p == '_')))
{
size_t len;
e2 = p;
len = (size_t)(e2 - e1);
if (len > 0)
{
memcpy(env, e1, len);
env[len] = 0;
val = getenv(env);
if (val) eina_strbuf_append(sb, val);
}
e1 = NULL;
eina_strbuf_append_char(sb, *p);
}
}
ret = eina_stringshare_add(eina_strbuf_string_get(sb));
eina_strbuf_free(sb);
return ret;
}
/**
* @internal
* @param key The user-dirs key to lookup
* @param fallback The fallback value to use
* @return Returns the directory related to the given key or the fallback
* @brief This tries to determine the correct directory name given the
* user-dirs key @a key and fallbacks @a fallback.
*/
static const char *
efreet_user_dir_get(const char *key, const char *fallback)
{
Eina_File *file = NULL;
Eina_File_Line *line;
Eina_Iterator *it = NULL;
const char *config_home;
char path[PATH_MAX];
char *ret = NULL;
config_home = efreet_config_home_get();
snprintf(path, sizeof(path), "%s/user-dirs.dirs", config_home);
file = eina_file_open(path, EINA_FALSE);
if (!file) goto fallback;
it = eina_file_map_lines(file);
if (!it) goto fallback;
EINA_ITERATOR_FOREACH(it, line)
{
const char *eq, *end;
if (line->length < 3) continue;
if (line->start[0] == '#') continue;
if (strncmp(line->start, "XDG", 3)) continue;
eq = memchr(line->start, '=', line->length);
if (!eq) continue;
if (strncmp(key, line->start, eq - line->start)) continue;
if (++eq >= line->end) continue;
if (*eq != '"') continue;
if (++eq >= line->end) continue;
end = memchr(eq, '"', line->end - eq);
if (!end) continue;
ret = alloca(end - eq + 1);
memcpy(ret, eq, end - eq);
ret[end - eq] = '\0';
break;
}
fallback:
if (it) eina_iterator_free(it);
if (file) eina_file_close(file);
if (!ret)
{
const char *home;
home = efreet_home_dir_get();
ret = alloca(strlen(home) + strlen(fallback) + 2);
sprintf(ret, "%s/%s", home, fallback);
}
return efreet_env_expand(ret);
}