/src/util.c

https://github.com/nesaro/uzbl · C · 180 lines · 123 code · 40 blank · 17 comment · 17 complexity · 26001986cce624a9a19647d1c12bb2dc MD5 · raw file

  1. #define _POSIX_SOURCE
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <string.h>
  5. #include "util.h"
  6. gchar* find_existing_file2(gchar *, const gchar *);
  7. const XDG_Var XDG[] = {
  8. { "XDG_CONFIG_HOME", "~/.config" },
  9. { "XDG_DATA_HOME", "~/.local/share" },
  10. { "XDG_CACHE_HOME", "~/.cache" },
  11. { "XDG_CONFIG_DIRS", "/etc/xdg" },
  12. { "XDG_DATA_DIRS", "/usr/local/share/:/usr/share/" },
  13. };
  14. /*@null@*/ gchar*
  15. get_xdg_var (XDG_Var xdg) {
  16. const gchar *actual_value = getenv(xdg.environmental);
  17. const gchar *home = getenv("HOME");
  18. if (!actual_value || !actual_value[0])
  19. actual_value = xdg.default_value;
  20. if (!actual_value)
  21. return NULL;
  22. return str_replace("~", home, actual_value);
  23. }
  24. /*@null@*/ gchar*
  25. find_xdg_file (int xdg_type, const char* basename) {
  26. /* xdg_type = 0 => config
  27. xdg_type = 1 => data
  28. xdg_type = 2 => cache */
  29. gchar *xdgv = get_xdg_var(XDG[xdg_type]);
  30. gchar *path = g_strconcat (xdgv, basename, NULL);
  31. g_free (xdgv);
  32. if (file_exists(path))
  33. return path;
  34. if (xdg_type == 2)
  35. return NULL;
  36. /* the file doesn't exist in the expected directory.
  37. * check if it exists in one of the system-wide directories. */
  38. char *system_dirs = get_xdg_var(XDG[3 + xdg_type]);
  39. path = find_existing_file2(system_dirs, basename);
  40. g_free(system_dirs);
  41. return path;
  42. }
  43. gboolean
  44. file_exists (const char * filename) {
  45. return (access(filename, F_OK) == 0);
  46. }
  47. char *
  48. str_replace (const char* search, const char* replace, const char* string) {
  49. gchar **buf;
  50. char *ret;
  51. if(!string)
  52. return NULL;
  53. buf = g_strsplit (string, search, -1);
  54. ret = g_strjoinv (replace, buf);
  55. g_strfreev(buf);
  56. return ret;
  57. }
  58. gboolean
  59. for_each_line_in_file(const gchar *path, void (*callback)(const gchar *l, void *c), void *user_data) {
  60. gchar *line = NULL;
  61. gsize len;
  62. GIOChannel *chan = g_io_channel_new_file(path, "r", NULL);
  63. if (!chan)
  64. return FALSE;
  65. while (g_io_channel_read_line(chan, &line, &len, NULL, NULL) == G_IO_STATUS_NORMAL) {
  66. callback(line, user_data);
  67. g_free(line);
  68. }
  69. g_io_channel_unref (chan);
  70. return TRUE;
  71. }
  72. /* This function searches the directories in the : separated ($PATH style)
  73. * string 'dirs' for a file named 'basename'. It returns the path of the first
  74. * file found, or NULL if none could be found.
  75. * NOTE: this function modifies the 'dirs' argument. */
  76. gchar*
  77. find_existing_file2(gchar *dirs, const gchar *basename) {
  78. char *saveptr = NULL;
  79. /* iterate through the : separated elements until we find our file. */
  80. char *tok = strtok_r(dirs, ":", &saveptr);
  81. char *path = g_strconcat (tok, "/", basename, NULL);
  82. while (!file_exists(path)) {
  83. g_free(path);
  84. tok = strtok_r(NULL, ":", &saveptr);
  85. if (!tok)
  86. return NULL; /* we've hit the end of the string */
  87. path = g_strconcat (tok, "/", basename, NULL);
  88. }
  89. return path;
  90. }
  91. /* search a PATH style string for an existing file+path combination.
  92. * everything after the last ':' is assumed to be the name of the file.
  93. * e.g. "/tmp:/home:a/file" will look for /tmp/a/file and /home/a/file.
  94. *
  95. * if there are no :s then the entire thing is taken to be the path. */
  96. gchar*
  97. find_existing_file(const gchar* path_list) {
  98. if(!path_list)
  99. return NULL;
  100. char *path_list_dup = g_strdup(path_list);
  101. char *basename = strrchr(path_list_dup, ':');
  102. if(!basename)
  103. return file_exists(path_list_dup) ? path_list_dup : NULL;
  104. basename[0] = '\0';
  105. basename++;
  106. char *result = find_existing_file2(path_list_dup, basename);
  107. g_free(path_list_dup);
  108. return result;
  109. }
  110. gchar*
  111. argv_idx(const GArray *a, const guint idx) {
  112. return g_array_index(a, gchar*, idx);
  113. }
  114. GString *
  115. append_escaped (GString *dest, const gchar *src) {
  116. g_assert(dest);
  117. g_assert(src);
  118. // Hint that we are going to append another string.
  119. int oldlen = dest->len;
  120. g_string_set_size (dest, dest->len + strlen(src) * 2);
  121. g_string_truncate (dest, oldlen);
  122. // Append src char by char with baddies escaped
  123. for (const gchar *p = src; *p; p++) {
  124. switch (*p) {
  125. case '\\':
  126. g_string_append (dest, "\\\\");
  127. break;
  128. case '\'':
  129. g_string_append (dest, "\\'");
  130. break;
  131. case '\n':
  132. g_string_append (dest, "\\n");
  133. break;
  134. default:
  135. g_string_append_c (dest, *p);
  136. break;
  137. }
  138. }
  139. return dest;
  140. }