summaryrefslogtreecommitdiffstats
path: root/xdg-user-dirs-update.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 13:40:30 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 13:40:30 +0000
commitad8b856c3b0d4d6055141a74664dbea4416c198d (patch)
tree8596d1a11d20a850e3316e27e51e422baa0aa1e5 /xdg-user-dirs-update.c
parentInitial commit. (diff)
downloadxdg-user-dirs-ad8b856c3b0d4d6055141a74664dbea4416c198d.tar.xz
xdg-user-dirs-ad8b856c3b0d4d6055141a74664dbea4416c198d.zip
Adding upstream version 0.17.upstream/0.17upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'xdg-user-dirs-update.c')
-rw-r--r--xdg-user-dirs-update.c1152
1 files changed, 1152 insertions, 0 deletions
diff --git a/xdg-user-dirs-update.c b/xdg-user-dirs-update.c
new file mode 100644
index 0000000..6a99db0
--- /dev/null
+++ b/xdg-user-dirs-update.c
@@ -0,0 +1,1152 @@
+#include <config.h>
+
+#define _GNU_SOURCE
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <libintl.h>
+#include <locale.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <iconv.h>
+#include <langinfo.h>
+
+typedef struct {
+ char *name;
+ char *path;
+} Directory;
+
+Directory backwards_compat_dirs[] = {
+ { "DESKTOP", "Desktop" },
+ { "TEMPLATES", "Templates" },
+ { "PUBLICSHARE", "Public" },
+ { NULL}
+};
+
+static Directory *default_dirs = NULL;
+static Directory *user_dirs = NULL;
+static int user_dirs_changed = 0;
+
+/* Config: */
+
+static int enabled = 1;
+static char *filename_encoding = NULL; /* NULL => utf8 */
+
+/* Args */
+static char *dummy_file = NULL;
+
+static iconv_t filename_converter = (iconv_t)(-1);
+
+static char *
+concat_strings (const char *first, ...)
+{
+ char *res;
+ const char *next;
+ va_list va;
+ int len;
+
+ res = strdup (first);
+ len = strlen (res) + 1;
+
+ va_start (va, first);
+ while ( (next = va_arg(va, const char *)) != NULL)
+ {
+ res = realloc (res, len + strlen (next) + 1);
+ strcat (res, next);
+ }
+
+ va_end(va);
+
+ return res;
+}
+
+static char *
+strdup_end (const char *start, const char *end)
+{
+ char *res;
+
+ res = malloc (end - start + 1);
+ memcpy (res, start, end - start);
+ res[end-start] = 0;
+ return res;
+}
+
+static int
+has_prefix (const char *str, const char *prefix)
+{
+ return strncmp (str, prefix, strlen (prefix)) == 0;
+}
+
+static char
+ascii_toupper (char c)
+{
+ if (c >= 'a' && c <= 'z')
+ c = (c - 'a') + 'A';
+ return c;
+}
+
+static void
+ascii_str_toupper (char *c)
+{
+ while (*c)
+ {
+ *c = ascii_toupper (*c);
+ c++;
+ }
+}
+
+static int
+is_space (char c)
+{
+ return c == ' ' || c == '\t';
+}
+
+static void
+remove_trailing_whitespace (char *s)
+{
+ int len;
+
+ len = strlen (s);
+ while (len > 0 && is_space (s[len-1]))
+ {
+ s[len-1] = 0;
+ len--;
+ }
+}
+
+static int
+is_regular_file (char *path)
+{
+ struct stat statbuf;
+ if (stat (path, &statbuf) == -1)
+ return 0;
+
+ return S_ISREG(statbuf.st_mode);
+}
+
+static int
+is_directory (char *path)
+{
+ struct stat statbuf;
+ if (stat (path, &statbuf) == -1)
+ return 0;
+
+ return S_ISDIR(statbuf.st_mode);
+}
+
+
+static int
+mkdir_all (char *path)
+{
+ char *p;
+ int revert;
+ int result;
+
+ path = strdup (path);
+
+ result = 1;
+ p = path;
+ while (*p)
+ {
+ /* skip initial slashes */
+ while (*p == '/')
+ p++;
+
+ while (*p && *p != '/')
+ p++;
+
+ revert = 0;
+ if (*p == '/')
+ {
+ *p = 0;
+ revert = 1;
+ }
+
+ if ((mkdir (path, 0755) == -1) &&
+ (errno != EEXIST))
+ {
+ result = 0;
+ break;
+ }
+
+ if (revert)
+ *p = '/';
+ }
+
+ free (path);
+ return result;
+}
+
+static char *
+shell_unescape (char *escaped)
+{
+ char *unescaped;
+ char *d;
+
+ unescaped = malloc (strlen (escaped) + 1);
+
+ d = unescaped;
+
+ while (*escaped)
+ {
+ if (*escaped == '\\' && *(escaped + 1) != 0)
+ escaped++;
+ *d++ = *escaped++;
+ }
+ *d = 0;
+ return unescaped;
+}
+
+static char *
+shell_escape (char *unescaped)
+{
+ char *escaped;
+ char *d;
+
+ escaped = malloc (strlen (unescaped) * 2 + 1);
+
+ d = escaped;
+
+ while (*unescaped)
+ {
+ if (*unescaped == '$' ||
+ *unescaped == '`' ||
+ *unescaped == '\\')
+ *d++ = '\\';
+ *d++ = *unescaped++;
+ }
+ *d = 0;
+ return escaped;
+}
+
+static char *
+filename_from_utf8 (const char *utf8_path)
+{
+ size_t res, len;
+ const char *in;
+ char *out, *outp;
+ size_t in_left, out_left, outbuf_size;
+ int done;
+
+ if (filename_converter == (iconv_t)(-1))
+ return strdup (utf8_path);
+
+ len = strlen (utf8_path);
+ outbuf_size = len + 1;
+
+ done = 0;
+ do
+ {
+ in = utf8_path;
+ in_left = len;
+ out = malloc (outbuf_size);
+ out_left = outbuf_size - 1;
+ outp = out;
+
+ res = iconv (filename_converter,
+ (ICONV_CONST char **)&in, &in_left,
+ &outp, &out_left);
+ if (res == (size_t)(-1) && errno == E2BIG)
+ {
+ free (out);
+ outbuf_size *= 2;
+ }
+ else
+ done = 1;
+ }
+ while (!done);
+
+ if (res == (size_t)(-1))
+ {
+ free (out);
+ return NULL;
+ }
+
+ /* zero terminate */
+ *outp = 0;
+ return out;
+}
+
+static char *
+get_home_dir (void)
+{
+ struct passwd *pw;
+ static char *home_dir = NULL;
+ const char *home_env;
+
+ if (home_dir != NULL)
+ return home_dir;
+
+ home_env = getenv ("HOME");
+
+ if (home_env && *home_env)
+ {
+ home_dir = strdup (home_env);
+ }
+ else
+ {
+ setpwent ();
+ pw = getpwuid (getuid ());
+ endpwent ();
+
+ if (pw && pw->pw_dir)
+ home_dir = strdup (pw->pw_dir);
+ }
+
+ return home_dir;
+}
+
+static char *
+get_user_config_file (const char *filename)
+{
+ char *config_home, *file;
+ int free_config_home;
+
+ config_home = getenv ("XDG_CONFIG_HOME");
+
+ free_config_home = 0;
+ if (config_home == NULL || config_home[0] == 0)
+ {
+ config_home = concat_strings (get_home_dir (), "/.config", NULL);
+ free_config_home = 1;
+ }
+
+ file = concat_strings (config_home, "/", filename, NULL);
+
+ if (free_config_home)
+ free (config_home);
+
+ return file;
+}
+
+static void
+freev (char **strs)
+{
+ int i;
+ if (strs)
+ {
+ for (i = 0; strs[i] != NULL; i++)
+ free (strs[i]);
+ free (strs);
+ }
+}
+
+static char **
+parse_colon_separated_dirs (const char *dirs)
+{
+ int numfiles;
+ char **paths;
+ const char *p;
+
+ numfiles = 0;
+ paths = malloc (sizeof (char *));
+ paths[0] = NULL;
+
+ p = dirs;
+ while (p != NULL && *p != 0)
+ {
+ int len;
+ const char *path;
+ char *colon;
+
+ path = p;
+ colon = strchr (path, ':');
+ if (colon)
+ {
+ len = colon - p;
+ p = colon + 1;
+ }
+ else
+ {
+ len = strlen (p);
+ p = NULL;
+ }
+
+ paths = realloc (paths, sizeof (char *) * (numfiles + 2));
+ paths[numfiles++] = strndup (path, len);
+ paths[numfiles] = NULL;
+ }
+
+ return paths;
+}
+
+static char **
+get_config_files (char *filename)
+{
+ int i;
+ int numfiles;
+ char *config_dirs;
+ char *file;
+ char **paths, **config_paths;
+
+ numfiles = 0;
+ paths = malloc (sizeof (char *));
+ paths[0] = NULL;
+
+ file = get_user_config_file (filename);
+ if (file)
+ {
+ if (is_regular_file (file))
+ {
+ paths = realloc (paths, sizeof (char *) * (numfiles + 2));
+ paths[numfiles++] = file;
+ paths[numfiles] = NULL;
+ }
+ else
+ free (file);
+ }
+
+ config_dirs = getenv ("XDG_CONFIG_DIRS");
+ if (config_dirs)
+ config_paths = parse_colon_separated_dirs (config_dirs);
+ else
+ config_paths = parse_colon_separated_dirs (XDGCONFDIR);
+
+ for (i = 0; config_paths[i] != NULL; i++)
+ {
+ file = concat_strings (config_paths[i], "/", filename, NULL);
+ if (is_regular_file (file))
+ {
+ paths = realloc (paths, sizeof (char *) * (numfiles + 2));
+ paths[numfiles++] = file;
+ paths[numfiles] = NULL;
+ }
+ else
+ free (file);
+ free (config_paths[i]);
+ }
+
+ free (config_paths);
+
+ return paths;
+}
+
+static Directory *
+add_directory (Directory *dirs, Directory *dir)
+{
+ Directory *new_dirs;
+ int i;
+
+ if (dirs == NULL)
+ {
+ new_dirs = malloc (sizeof (Directory) * 2);
+ new_dirs[0] = *dir;
+ new_dirs[1].name = NULL;
+ }
+ else
+ {
+ for (i = 0; dirs[i].name != NULL; i++)
+ ;
+ new_dirs = realloc (dirs, (i + 2) * sizeof (Directory));
+ new_dirs[i] = *dir;
+ new_dirs[i+1].name = NULL;
+ }
+ return new_dirs;
+}
+
+static int
+is_true (const char *str)
+{
+ while (is_space (*str))
+ str++;
+
+ if (*str == '1' ||
+ has_prefix (str, "True") ||
+ has_prefix (str, "true"))
+ return 1;
+ return 0;
+}
+
+static void
+load_config (char *path)
+{
+ FILE *file;
+ char buffer[512];
+ char *p;
+ int len;
+
+ file = fopen (path, "r");
+ if (file == NULL)
+ return;
+
+ while (fgets (buffer, sizeof (buffer), file))
+ {
+ /* Remove newline at end */
+ len = strlen (buffer);
+ if (len > 0 && buffer[len-1] == '\n')
+ buffer[len-1] = 0;
+
+ p = buffer;
+ /* Skip whitespace */
+ while (is_space (*p))
+ p++;
+
+ if (*p == '#')
+ continue;
+
+ remove_trailing_whitespace (p);
+
+ if (has_prefix (p, "enabled="))
+ {
+ p += strlen ("enabled=");
+ enabled = is_true (p);
+ }
+ if (has_prefix (p, "filename_encoding="))
+ {
+ p += strlen ("filename_encoding=");
+
+ while (is_space (*p))
+ p++;
+
+ ascii_str_toupper (p);
+ remove_trailing_whitespace (p);
+ if (filename_encoding)
+ free (filename_encoding);
+
+ if (strcmp (p, "UTF8") == 0 ||
+ strcmp (p, "UTF-8") == 0)
+ filename_encoding = NULL;
+ else if (strcmp (p, "LOCALE") == 0)
+ filename_encoding = strdup (nl_langinfo (CODESET));
+ else
+ filename_encoding = strdup (p);
+ }
+ }
+
+ fclose (file);
+}
+
+static void
+load_all_configs (void)
+{
+ char **paths;
+ int i;
+
+ paths = get_config_files ("user-dirs.conf");
+
+ /* Load config files in reverse */
+ for (i = 0; paths[i] != NULL; i++)
+ ;
+
+ while (--i >= 0)
+ load_config (paths[i]);
+
+ freev (paths);
+}
+
+static void
+load_default_dirs (void)
+{
+ FILE *file;
+ char buffer[512];
+ char *p;
+ char *key, *key_end, *value;
+ int len;
+ Directory dir;
+ char **paths;
+
+ paths = get_config_files ("user-dirs.defaults");
+ if (paths[0] == NULL)
+ {
+ fprintf (stderr, "No default user directories\n");
+ exit (1);
+ }
+
+ file = fopen (paths[0], "r");
+ if (file == NULL)
+ {
+ fprintf (stderr, "Can't open %s\n", paths[0]);
+ exit (1);
+ }
+
+ while (fgets (buffer, sizeof (buffer), file))
+ {
+ /* Remove newline at end */
+ len = strlen (buffer);
+ if (len > 0 && buffer[len-1] == '\n')
+ buffer[len-1] = 0;
+
+ p = buffer;
+ /* Skip whitespace */
+ while (is_space (*p))
+ p++;
+
+ if (*p == '#')
+ continue;
+
+ key = p;
+ while (*p && !is_space (*p) && * p != '=')
+ p++;
+
+ key_end = p;
+
+ while (is_space (*p))
+ p++;
+ if (*p == '=')
+ p++;
+ while (is_space (*p))
+ p++;
+
+ value = p;
+
+ *key_end = 0;
+
+ if (*key == 0 || *value == 0)
+ continue;
+
+ dir.name = strdup (key);
+ dir.path = strdup (value);
+ default_dirs = add_directory (default_dirs, &dir);
+ }
+
+ fclose (file);
+ freev (paths);
+}
+
+static void
+load_user_dirs (void)
+{
+ FILE *file;
+ char buffer[512];
+ char *p;
+ char *key, *key_end, *value, *value_end;
+ int len;
+ Directory dir;
+ char *user_config_file;
+
+ user_config_file = get_user_config_file ("user-dirs.dirs");
+
+ file = fopen (user_config_file, "r");
+ free (user_config_file);
+
+ if (file == NULL)
+ return;
+
+ while (fgets (buffer, sizeof (buffer), file))
+ {
+ /* Remove newline at end */
+ len = strlen (buffer);
+ if (len > 0 && buffer[len-1] == '\n')
+ buffer[len-1] = 0;
+
+ p = buffer;
+ /* Skip whitespace */
+ while (is_space (*p))
+ p++;
+
+ /* Skip comment lines */
+ if (*p == '#')
+ continue;
+
+ if (!has_prefix(p, "XDG_"))
+ continue;
+ p += 4;
+ key = p;
+
+ while (*p && !is_space (*p) && * p != '=')
+ p++;
+
+ if (*p == 0)
+ continue;
+
+ key_end = p - 4;
+ if (key_end <= key ||
+ !has_prefix (key_end, "_DIR"))
+ continue;
+
+ if (*p == '=')
+ p++;
+
+ while (is_space (*p))
+ p++;
+
+ if (*p++ != '"')
+ continue;
+
+
+ if (has_prefix (p, "$HOME"))
+ {
+ p += 5;
+ if (*p == '/')
+ p++;
+ else if (*p != '"' && *p != 0)
+ continue; /* Not ending after $HOME, nor followed by slash. Ignore */
+ }
+ else if (*p != '/')
+ continue;
+ value = p;
+
+ while (*p)
+ {
+ if (*p == '"')
+ break;
+ if (*p == '\\' && *(p+1) != 0)
+ p++;
+
+ p++;
+ }
+ value_end = p;
+
+ *key_end = 0;
+ *value_end = 0;
+
+ if (*key == 0)
+ continue;
+
+ dir.name = strdup (key);
+ dir.path = shell_unescape (value);
+ user_dirs = add_directory (user_dirs, &dir);
+ }
+
+ fclose (file);
+}
+
+static void
+save_locale (void)
+{
+ FILE *file;
+ char *user_locale_file;
+ char *locale, *dot;
+
+ user_locale_file = get_user_config_file ("user-dirs.locale");
+ file = fopen (user_locale_file, "w");
+ free (user_locale_file);
+
+ if (file == NULL)
+ {
+ fprintf (stderr, "Can't save user-dirs.locale\n");
+ return;
+ }
+
+ locale = strdup (setlocale (LC_MESSAGES, NULL));
+ /* Skip encoding part */
+ dot = strchr (locale, '.');
+ if (dot)
+ *dot = 0;
+ fprintf (file, "%s", locale);
+ free (locale);
+ fclose (file);
+}
+
+static int
+save_user_dirs (void)
+{
+ FILE *file;
+ char *user_config_file;
+ char *tmp_file;
+ int i;
+ char *escaped;
+ int tmp_fd;
+ int res;
+ char *dir, *slash;
+ struct stat stat_buf;
+
+ res = 1;
+
+ tmp_file = NULL;
+ if (dummy_file)
+ user_config_file = strdup (dummy_file);
+ else
+ user_config_file = get_user_config_file ("user-dirs.dirs");
+
+ dir = strdup (user_config_file);
+ slash = strrchr (dir, '/');
+ if (slash)
+ *slash = 0;
+
+ if (stat (dir, &stat_buf) == -1 && errno == ENOENT)
+ {
+ if (mkdir (dir, 0700) == -1)
+ {
+ free (dir);
+ fprintf (stderr, "Can't save user-dirs.dirs, failed to create directory\n");
+ res = 0;
+ goto out;
+ }
+ }
+ free (dir);
+
+ tmp_file = malloc (strlen (user_config_file) + 6 + 1);
+ strcpy (tmp_file, user_config_file);
+ strcat (tmp_file, "XXXXXX");
+
+ tmp_fd = mkstemp (tmp_file);
+ if (tmp_fd == -1)
+ {
+ fprintf (stderr, "Can't save user-dirs.dirs\n");
+ res = 0;
+ goto out;
+ }
+
+ file = fdopen (tmp_fd, "w");
+ if (file == NULL)
+ {
+ unlink (tmp_file);
+ fprintf (stderr, "Can't save user-dirs.dirs\n");
+ res = 0;
+ goto out;
+ }
+
+ fprintf (file, "# This file is written by xdg-user-dirs-update\n");
+ fprintf (file, "# If you want to change or add directories, just edit the line you're\n");
+ fprintf (file, "# interested in. All local changes will be retained on the next run.\n");
+ fprintf (file, "# Format is XDG_xxx_DIR=\"$HOME/yyy\", where yyy is a shell-escaped\n");
+ fprintf (file, "# homedir-relative path, or XDG_xxx_DIR=\"/yyy\", where /yyy is an\n");
+ fprintf (file, "# absolute path. No other format is supported.\n");
+ fprintf (file, "# \n");
+
+ if (user_dirs)
+ {
+ for (i = 0; user_dirs[i].name != NULL; i++)
+ {
+ escaped = shell_escape (user_dirs[i].path);
+ fprintf (file, "XDG_%s_DIR=\"%s%s\"\n",
+ user_dirs[i].name,
+ (*escaped == '/')?"":"$HOME/",
+ escaped);
+ free (escaped);
+ }
+ }
+
+ fclose (file);
+
+ if (rename (tmp_file, user_config_file) == -1)
+ {
+ unlink (tmp_file);
+ fprintf (stderr, "Can't save user-dirs.dirs\n");
+ res = 0;
+ }
+
+ out:
+ if (tmp_file)
+ free (tmp_file);
+ free (user_config_file);
+ return res;
+}
+
+
+static char *
+localize_path_name (const char *path)
+{
+ char *res;
+ const char *element, *element_end;
+ char *element_copy;
+ char *translated;
+ int has_slash;
+
+ res = strdup ("");
+
+ while (*path)
+ {
+ has_slash = 0;
+ while (*path == '/')
+ {
+ path++;
+ has_slash = 1;
+ }
+
+ element = path;
+ while (*path && *path != '/')
+ path++;
+ element_end = path;
+
+ element_copy = strdup_end (element, element_end);
+ translated = gettext (element_copy);
+
+ res = realloc (res, strlen (res) + 1 + strlen (translated) + 1);
+ if (has_slash)
+ strcat (res, "/");
+ strcat (res, translated);
+
+ free (element_copy);
+ }
+
+ return res;
+}
+
+static Directory *
+lookup_backwards_compat (Directory *dir)
+{
+ int i;
+ for (i = 0; backwards_compat_dirs[i].name != NULL; i++)
+ {
+ if (strcmp (dir->name, backwards_compat_dirs[i].name) == 0)
+ return &backwards_compat_dirs[i];
+ }
+ return NULL;
+}
+
+static Directory *
+find_dir (Directory *dirs, const char *name)
+{
+ int i;
+
+ if (dirs == NULL)
+ return NULL;
+
+ for (i = 0; dirs[i].name != NULL; i++)
+ {
+ if (strcmp (dirs[i].name, name) == 0)
+ return &dirs[i];
+ }
+ return NULL;
+}
+
+static void
+create_dirs (int force)
+{
+ int i;
+ Directory dir;
+ Directory *user_dir, *default_dir, *compat_dir;
+ char *path_name, *relative_path_name, *translated_name;
+
+ if (default_dirs == NULL)
+ return;
+
+ for (i = 0; default_dirs[i].name != NULL; i++)
+ {
+ default_dir = &default_dirs[i];
+ user_dir = NULL;
+ user_dir = find_dir (user_dirs, default_dir->name);
+
+ if (user_dir && !force)
+ {
+ if (user_dir->path[0] == '/')
+ path_name = strdup (user_dir->path);
+ else
+ path_name = concat_strings (get_home_dir (), "/", user_dir->path, NULL);
+ if (!is_directory (path_name))
+ {
+ fprintf (stderr, "%s was removed, reassigning %s to homedir\n",
+ path_name, user_dir->name);
+ free (user_dir->path);
+ user_dir->path = strdup ("");
+ user_dirs_changed = 1;
+ }
+ free (path_name);
+ continue;
+ }
+
+ path_name = NULL;
+ relative_path_name = NULL;
+ if (user_dir == NULL && !force)
+ {
+ /* New default dir. Check if its an old named dir. We want to
+ reuse that if it exists. */
+ compat_dir = lookup_backwards_compat (default_dir);
+ if (compat_dir)
+ {
+ path_name = concat_strings (get_home_dir (), "/", compat_dir->path, NULL);
+ if (!is_directory (path_name))
+ {
+ free (path_name);
+ path_name = NULL;
+ }
+ else
+ relative_path_name = strdup (compat_dir->path);
+ }
+ }
+
+ if (path_name == NULL)
+ {
+ translated_name = localize_path_name (default_dir->path);
+ relative_path_name = filename_from_utf8 (translated_name);
+ if (relative_path_name == NULL)
+ relative_path_name = strdup (translated_name);
+ free (translated_name);
+ if (relative_path_name[0] == '/')
+ path_name = strdup (relative_path_name); /* default path was absolute, not homedir relative */
+ else
+ path_name = concat_strings (get_home_dir (), "/", relative_path_name, NULL);
+ }
+
+ if (user_dir == NULL || strcmp (relative_path_name, user_dir->path) != 0)
+ {
+ /* Don't make the directories if we're writing a dummy output file */
+ if (dummy_file == NULL &&
+ !mkdir_all (path_name))
+ {
+ fprintf (stderr, "Can't create dir %s\n", path_name);
+ }
+ else
+ {
+ user_dirs_changed = 1;
+ if (user_dir == NULL)
+ {
+ dir.name = strdup (default_dir->name);
+ dir.path = strdup (relative_path_name);
+ user_dirs = add_directory (user_dirs, &dir);
+ }
+ else
+ {
+ /* We forced an update */
+ fprintf (stdout, "Moving %s directory from %s to %s\n",
+ default_dir->name, user_dir->path, relative_path_name);
+ free (user_dir->path);
+ user_dir->path = strdup (relative_path_name);
+ }
+ }
+ }
+
+ free (relative_path_name);
+ free (path_name);
+ }
+}
+
+int
+main (int argc, char *argv[])
+{
+ int force;
+ int i;
+ int was_empty;
+ char *set_dir = NULL;
+ char *set_value = NULL;
+ char *locale_dir = NULL;
+
+ setlocale (LC_ALL, "");
+
+ if (is_directory (LOCALEDIR))
+ locale_dir = strdup (LOCALEDIR);
+ else
+ {
+ /* In case LOCALEDIR does not exist, e.g. xdg-user-dirs is installed in
+ * a different location than the one determined at compile time, look
+ * through the XDG_DATA_DIRS environment variable for alternate locations
+ * of the locale files */
+ char *data_dirs = getenv ("XDG_DATA_DIRS");
+ if (data_dirs)
+ {
+ char **data_paths;
+
+ data_paths = parse_colon_separated_dirs (data_dirs);
+ for (i = 0; data_paths[i] != NULL; i++)
+ {
+ if (!locale_dir)
+ {
+ char *dir = NULL;
+ dir = concat_strings (data_paths[i], "/", "locale", NULL);
+ if (is_directory (dir))
+ locale_dir = dir;
+ else
+ free (dir);
+ }
+ free (data_paths[i]);
+ }
+ free (data_paths);
+ }
+ }
+
+ bindtextdomain (GETTEXT_PACKAGE, locale_dir);
+ free (locale_dir);
+
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+ textdomain (GETTEXT_PACKAGE);
+
+ force = 0;
+ for (i = 1; i < argc; i++)
+ {
+ if (strcmp (argv[i], "--help") == 0)
+ {
+ printf ("Usage: xdg-user-dirs-update [--force] [--dummy-output <path>] [--set DIR path]\n");
+ exit (0);
+ }
+ else if (strcmp (argv[i], "--force") == 0)
+ force = 1;
+ else if (strcmp (argv[i], "--dummy-output") == 0 && i + 1 < argc)
+ dummy_file = argv[++i];
+ else if (strcmp (argv[i], "--set") == 0 && i + 2 < argc)
+ {
+ set_dir = argv[++i];
+ set_value = argv[++i];
+
+ if (*set_value != '/')
+ {
+ printf ("directory value must be absolute path (was %s)\n", set_value);
+ exit (1);
+ }
+ }
+ else
+ {
+ printf ("Invalid argument %s\n", argv[i]);
+ exit (1);
+ }
+ }
+
+ load_all_configs ();
+ if (filename_encoding)
+ {
+ filename_converter = iconv_open (filename_encoding, "UTF-8");
+ if (filename_converter == (iconv_t)(-1))
+ {
+ fprintf (stderr, "Can't convert from UTF-8 to %s\n", filename_encoding);
+ return 1;
+ }
+ }
+
+ if (set_dir != NULL)
+ {
+ Directory *dir;
+ char *path, *home;
+ /* Set a key */
+
+ load_user_dirs ();
+
+ home = get_home_dir ();
+
+ path = set_value;
+ if (has_prefix (path, home))
+ {
+ path += strlen (home);
+ while (*path == '/')
+ path++;
+ }
+
+ dir = find_dir (user_dirs, set_dir);
+ if (dir != NULL)
+ {
+ free (dir->path);
+ dir->path = strdup (path);
+ }
+ else
+ {
+ Directory new_dir;
+
+ new_dir.name = strdup (set_dir);
+ new_dir.path = strdup (path);
+
+ user_dirs = add_directory (user_dirs, &new_dir);
+ }
+ if (!save_user_dirs ())
+ return 1;
+ }
+ else
+ {
+
+ /* default: update */
+ if (!enabled)
+ return 0;
+
+ load_default_dirs ();
+ load_user_dirs ();
+
+ was_empty = (user_dirs == NULL) || (user_dirs->name == NULL);
+
+ create_dirs (force);
+
+ if (user_dirs_changed)
+ {
+ if (!save_user_dirs ())
+ return 1;
+
+ if ((force || was_empty) && dummy_file == NULL)
+ save_locale ();
+ }
+
+ }
+ return 0;
+}