diff options
Diffstat (limited to 'src/util.c')
-rw-r--r-- | src/util.c | 166 |
1 files changed, 118 insertions, 48 deletions
@@ -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; } |