summaryrefslogtreecommitdiff
path: root/src/common.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/common.c')
-rw-r--r--src/common.c132
1 files changed, 87 insertions, 45 deletions
diff --git a/src/common.c b/src/common.c
index 2907159..8f7ffd1 100644
--- a/src/common.c
+++ b/src/common.c
@@ -1359,6 +1359,58 @@ get_xdg_home_dir (struct str *output, const char *var, const char *def)
}
}
+static void
+get_xdg_config_dirs (struct str_vector *out)
+{
+ struct str config_home;
+ str_init (&config_home);
+ get_xdg_home_dir (&config_home, "XDG_CONFIG_HOME", ".config");
+ str_vector_add (out, config_home.str);
+ str_free (&config_home);
+
+ const char *xdg_config_dirs;
+ if ((xdg_config_dirs = getenv ("XDG_CONFIG_DIRS")))
+ split_str_ignore_empty (xdg_config_dirs, ':', out);
+}
+
+static char *
+resolve_config_filename (const char *filename)
+{
+ // Absolute path is absolute
+ if (*filename == '/')
+ return xstrdup (filename);
+
+ struct str_vector paths;
+ str_vector_init (&paths);
+ get_xdg_config_dirs (&paths);
+
+ struct str file;
+ str_init (&file);
+
+ char *result = NULL;
+ for (unsigned i = 0; i < paths.len; i++)
+ {
+ // As per spec, relative paths are ignored
+ if (*paths.vector[i] != '/')
+ continue;
+
+ str_reset (&file);
+ str_append_printf (&file, "%s/" PROGRAM_NAME "/%s",
+ paths.vector[i], filename);
+
+ struct stat st;
+ if (!stat (file.str, &st))
+ {
+ result = str_steal (&file);
+ break;
+ }
+ }
+
+ str_vector_free (&paths);
+ str_free (&file);
+ return result;
+}
+
static size_t io_error_domain_tag;
#define IO_ERROR (error_resolve_domain (&io_error_domain_tag))
@@ -1729,45 +1781,6 @@ struct config_item
const char *description;
};
-static FILE *
-get_config_file (void)
-{
- struct str_vector paths;
- struct str config_home, file;
- const char *xdg_config_dirs;
- unsigned i;
- FILE *fp = NULL;
-
- str_vector_init (&paths);
-
- str_init (&config_home);
- get_xdg_home_dir (&config_home, "XDG_CONFIG_HOME", ".config");
- str_vector_add (&paths, config_home.str);
- str_free (&config_home);
-
- if ((xdg_config_dirs = getenv ("XDG_CONFIG_DIRS")))
- split_str_ignore_empty (xdg_config_dirs, ':', &paths);
-
- str_init (&file);
- for (i = 0; i < paths.len; i++)
- {
- // As per spec, relative paths are ignored
- if (*paths.vector[i] != '/')
- continue;
-
- str_reset (&file);
- str_append (&file, paths.vector[i]);
- str_append (&file, "/" PROGRAM_NAME "/" PROGRAM_NAME ".conf");
-
- if ((fp = fopen (file.str, "r")))
- break;
- }
-
- str_free (&file);
- str_vector_free (&paths);
- return fp;
-}
-
static void
load_config_defaults (struct str_map *config, const struct config_item *table)
{
@@ -1781,16 +1794,23 @@ load_config_defaults (struct str_map *config, const struct config_item *table)
static bool
read_config_file (struct str_map *config, struct error **e)
{
- struct str line;
- FILE *fp = get_config_file ();
- unsigned line_no = 0;
- bool errors = false;
+ char *filename = resolve_config_filename (PROGRAM_NAME ".conf");
+ if (!filename)
+ return true;
+ FILE *fp = fopen (filename, "r");
if (!fp)
- return true;
+ {
+ error_set (e, IO_ERROR, IO_ERROR_FAILED,
+ "could not open `%s' for reading: %s", filename, strerror (errno));
+ return false;
+ }
+ struct str line;
str_init (&line);
- for (line_no = 1; read_line (fp, &line); line_no++)
+
+ bool errors = false;
+ for (unsigned line_no = 1; read_line (fp, &line); line_no++)
{
char *start = line.str;
if (*start == '#')
@@ -1894,3 +1914,25 @@ error:
return NULL;
}
+
+static void
+call_write_default_config (const char *hint, const struct config_item *table)
+{
+ static const char *prolog =
+ "# " PROGRAM_NAME " " PROGRAM_VERSION " configuration file\n"
+ "#\n"
+ "# Relative paths are searched for in ${XDG_CONFIG_HOME:-~/.config}\n"
+ "# /" PROGRAM_NAME " as well as in $XDG_CONFIG_DIRS/" PROGRAM_NAME "\n"
+ "\n";
+
+ struct error *e = NULL;
+ char *filename = write_default_config (hint, prolog, table, &e);
+ if (!filename)
+ {
+ print_fatal ("%s", e->message);
+ error_free (e);
+ exit (EXIT_FAILURE);
+ }
+ print_status ("configuration written to `%s'", filename);
+ free (filename);
+}