aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/util.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/util.c')
-rw-r--r--src/util.c166
1 files changed, 118 insertions, 48 deletions
diff --git a/src/util.c b/src/util.c
index c9c728e..8f6c349 100644
--- a/src/util.c
+++ b/src/util.c
@@ -6,8 +6,9 @@
#include "util.h"
-const XDG_Var XDG[] =
-{
+gchar* find_existing_file2(gchar *, const gchar *);
+
+const XDG_Var XDG[] = {
{ "XDG_CONFIG_HOME", "~/.config" },
{ "XDG_DATA_HOME", "~/.local/share" },
{ "XDG_CACHE_HOME", "~/.cache" },
@@ -17,56 +18,41 @@ const XDG_Var XDG[] =
/*@null@*/ gchar*
get_xdg_var (XDG_Var xdg) {
- const gchar* actual_value = getenv (xdg.environmental);
- const gchar* home = getenv ("HOME");
- gchar* return_value;
-
- if (! actual_value || strcmp (actual_value, "") == 0) {
- if (xdg.default_value) {
- return_value = str_replace ("~", home, xdg.default_value);
- } else {
- return_value = NULL;
- }
- } else {
- return_value = str_replace("~", home, actual_value);
- }
+ const gchar *actual_value = getenv(xdg.environmental);
+ const gchar *home = getenv("HOME");
- return return_value;
+ if (!actual_value || !actual_value[0])
+ actual_value = xdg.default_value;
+
+ if (!actual_value)
+ return NULL;
+
+ return str_replace("~", home, actual_value);
}
/*@null@*/ gchar*
-find_xdg_file (int xdg_type, const char* filename) {
+find_xdg_file (int xdg_type, const char* basename) {
/* xdg_type = 0 => config
xdg_type = 1 => data
- xdg_type = 2 => cache*/
+ xdg_type = 2 => cache */
- gchar* xdgv = get_xdg_var (XDG[xdg_type]);
- gchar* temporary_file = g_strconcat (xdgv, filename, NULL);
+ gchar *xdgv = get_xdg_var(XDG[xdg_type]);
+ gchar *path = g_strconcat (xdgv, basename, NULL);
g_free (xdgv);
- gchar* temporary_string;
- char* saveptr;
- char* buf;
-
- if (! file_exists (temporary_file) && xdg_type != 2) {
- buf = get_xdg_var (XDG[3 + xdg_type]);
- temporary_string = (char *) strtok_r (buf, ":", &saveptr);
- g_free(buf);
+ if (file_exists(path))
+ return path;
- while ((temporary_string = (char * ) strtok_r (NULL, ":", &saveptr)) && ! file_exists (temporary_file)) {
- g_free (temporary_file);
- temporary_file = g_strconcat (temporary_string, filename, NULL);
- }
- }
+ if (xdg_type == 2)
+ return NULL;
- //g_free (temporary_string); - segfaults.
+ /* the file doesn't exist in the expected directory.
+ * check if it exists in one of the system-wide directories. */
+ char *system_dirs = get_xdg_var(XDG[3 + xdg_type]);
+ path = find_existing_file2(system_dirs, basename);
+ g_free(system_dirs);
- if (file_exists (temporary_file)) {
- return temporary_file;
- } else {
- g_free(temporary_file);
- return NULL;
- }
+ return path;
}
gboolean
@@ -96,15 +82,99 @@ for_each_line_in_file(const gchar *path, void (*callback)(const gchar *l, void *
GIOChannel *chan = g_io_channel_new_file(path, "r", NULL);
- if (chan) {
- while (g_io_channel_read_line(chan, &line, &len, NULL, NULL) == G_IO_STATUS_NORMAL) {
- callback(line, user_data);
- g_free(line);
- }
- g_io_channel_unref (chan);
+ if (!chan)
+ return FALSE;
- return TRUE;
+ while (g_io_channel_read_line(chan, &line, &len, NULL, NULL) == G_IO_STATUS_NORMAL) {
+ callback(line, user_data);
+ g_free(line);
}
- return FALSE;
+ g_io_channel_unref (chan);
+
+ return TRUE;
+}
+
+/* This function searches the directories in the : separated ($PATH style)
+ * string 'dirs' for a file named 'basename'. It returns the path of the first
+ * file found, or NULL if none could be found.
+ * NOTE: this function modifies the 'dirs' argument. */
+gchar*
+find_existing_file2(gchar *dirs, const gchar *basename) {
+ char *saveptr = NULL;
+
+ /* iterate through the : separated elements until we find our file. */
+ char *tok = strtok_r(dirs, ":", &saveptr);
+ char *path = g_strconcat (tok, "/", basename, NULL);
+
+ while (!file_exists(path)) {
+ g_free(path);
+
+ tok = strtok_r(NULL, ":", &saveptr);
+ if (!tok)
+ return NULL; /* we've hit the end of the string */
+
+ path = g_strconcat (tok, "/", basename, NULL);
+ }
+
+ return path;
+}
+
+/* search a PATH style string for an existing file+path combination.
+ * everything after the last ':' is assumed to be the name of the file.
+ * e.g. "/tmp:/home:a/file" will look for /tmp/a/file and /home/a/file.
+ *
+ * if there are no :s then the entire thing is taken to be the path. */
+gchar*
+find_existing_file(const gchar* path_list) {
+ if(!path_list)
+ return NULL;
+
+ char *path_list_dup = g_strdup(path_list);
+
+ char *basename = strrchr(path_list_dup, ':');
+ if(!basename)
+ return path_list_dup;
+
+ basename[0] = '\0';
+ basename++;
+
+ char *result = find_existing_file2(path_list_dup, basename);
+ g_free(path_list_dup);
+ return result;
+}
+
+gchar*
+argv_idx(const GArray *a, const guint idx) {
+ return g_array_index(a, gchar*, idx);
+}
+
+GString *
+append_escaped (GString *dest, const gchar *src) {
+ g_assert(dest);
+ g_assert(src);
+
+ // Hint that we are going to append another string.
+ int oldlen = dest->len;
+ g_string_set_size (dest, dest->len + strlen(src) * 2);
+ g_string_truncate (dest, oldlen);
+
+ // Append src char by char with baddies escaped
+ for (const gchar *p = src; *p; p++) {
+ switch (*p) {
+ case '\\':
+ g_string_append (dest, "\\\\");
+ break;
+ case '\'':
+ g_string_append (dest, "\\'");
+ break;
+ case '\n':
+ g_string_append (dest, "\\n");
+ break;
+ default:
+ g_string_append_c (dest, *p);
+ break;
+ }
+ }
+ return dest;
}