Resolve paths relative to XDG config. paths
This should make the programs an awful lot less painful to set up.
This commit is contained in:
134
src/common.c
134
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;
|
||||
|
||||
if (!fp)
|
||||
char *filename = resolve_config_filename (PROGRAM_NAME ".conf");
|
||||
if (!filename)
|
||||
return true;
|
||||
|
||||
FILE *fp = fopen (filename, "r");
|
||||
if (!fp)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user