From 8b2e41ed8ffac0494763495896c6a80a9e9db543 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?P=C5=99emysl=20Janouch?=
Date: Sun, 13 Dec 2015 22:10:56 +0100
Subject: [PATCH] Add read_file() and write_file()
And refactor the simple configuration module a bit.
---
liberty.c | 135 +++++++++++++++++++++++++++++++++++-------------------
1 file changed, 89 insertions(+), 46 deletions(-)
diff --git a/liberty.c b/liberty.c
index ba5a64d..d71ce89 100644
--- a/liberty.c
+++ b/liberty.c
@@ -2946,6 +2946,67 @@ regex_cache_match (struct str_map *cache, const char *regex, int flags,
return regexec (re, s, 0, NULL, 0) != REG_NOMATCH;
}
+// --- Simple file I/O ---------------------------------------------------------
+
+static bool
+read_file (const char *filename, struct str *output, struct error **e)
+{
+ FILE *fp = fopen (filename, "rb");
+ if (!fp)
+ {
+ error_set (e, "could not open `%s' for reading: %s",
+ filename, strerror (errno));
+ return false;
+ }
+
+ char buf[BUFSIZ];
+ size_t len;
+
+ while ((len = fread (buf, 1, sizeof buf, fp)) == sizeof buf)
+ str_append_data (output, buf, len);
+ str_append_data (output, buf, len);
+
+ bool success = !ferror (fp);
+ fclose (fp);
+
+ if (success)
+ return true;
+
+ error_set (e, "error while reading `%s': %s",
+ filename, strerror (errno));
+ return false;
+}
+
+/// Overwrites filename contents with data; creates directories as needed
+static bool
+write_file (const char *filename, const struct str *data, struct error **e)
+{
+ char *dir = xstrdup (filename);
+ bool parents_created = mkdir_with_parents (dirname (dir), e);
+ free (dir);
+ if (!parents_created)
+ return false;
+
+ FILE *fp = fopen (filename, "w");
+ if (!fp)
+ {
+ error_set (e, "could not open `%s' for writing: %s",
+ filename, strerror (errno));
+ return false;
+ }
+
+ errno = 0;
+ fwrite (data->str, data->len, 1, fp);
+ fclose (fp);
+
+ if (errno)
+ {
+ error_set (e, "writing to `%s' failed: %s", filename, strerror (errno));
+ return false;
+ }
+ return true;
+}
+
// --- Simple configuration ----------------------------------------------------
// The keys are stripped of surrounding whitespace, the values are not.
@@ -3023,75 +3084,57 @@ simple_config_update_from_file (struct str_map *config, struct error **e)
}
static char *
-simple_config_write_default (const char *filename, const char *prolog,
- const struct simple_config_item *table, struct error **e)
+write_configuration_file (const char *path_hint, const struct str *data,
+ struct error **e)
{
- struct str path, base;
-
+ struct str path;
str_init (&path);
- str_init (&base);
- if (filename)
- {
- char *tmp = xstrdup (filename);
- str_append (&path, dirname (tmp));
- strcpy (tmp, filename);
- str_append (&base, basename (tmp));
- free (tmp);
- }
+ if (path_hint)
+ str_append (&path, path_hint);
else
{
get_xdg_home_dir (&path, "XDG_CONFIG_HOME", ".config");
- str_append (&path, "/" PROGRAM_NAME);
- str_append (&base, PROGRAM_NAME ".conf");
+ str_append (&path, "/" PROGRAM_NAME "/" PROGRAM_NAME ".conf");
}
- if (!mkdir_with_parents (path.str, e))
- goto error;
-
- str_append_c (&path, '/');
- str_append_str (&path, &base);
-
- FILE *fp = fopen (path.str, "w");
- if (!fp)
+ if (!write_file (path.str, data, e))
{
- error_set (e, "could not open `%s' for writing: %s",
- path.str, strerror (errno));
- goto error;
+ str_free (&path);
+ return NULL;
}
+ return str_steal (&path);
+}
+
+static char *
+simple_config_write_default (const char *path_hint, const char *prolog,
+ const struct simple_config_item *table, struct error **e)
+{
+ struct str data;
+ str_init (&data);
if (prolog)
- fputs (prolog, fp);
+ str_append (&data, prolog);
- errno = 0;
for (; table->key != NULL; table++)
{
- fprintf (fp, "# %s\n", table->description);
+ str_append_printf (&data, "# %s\n", table->description);
if (table->default_value)
- fprintf (fp, "%s=%s\n", table->key, table->default_value);
+ str_append_printf (&data, "%s=%s\n",
+ table->key, table->default_value);
else
- fprintf (fp, "#%s=\n", table->key);
- }
- fclose (fp);
- if (errno)
- {
- error_set (e, "writing to `%s' failed: %s", path.str, strerror (errno));
- goto error;
+ str_append_printf (&data, "#%s=\n", table->key);
}
- str_free (&base);
- return str_steal (&path);
-
-error:
- str_free (&base);
- str_free (&path);
- return NULL;
+ char *path = write_configuration_file (path_hint, &data, e);
+ str_free (&data);
+ return path;
}
/// Convenience wrapper suitable for most simple applications
static void
call_simple_config_write_default
- (const char *hint, const struct simple_config_item *table)
+ (const char *path_hint, const struct simple_config_item *table)
{
static const char *prolog =
"# " PROGRAM_NAME " " PROGRAM_VERSION " configuration file\n"
@@ -3101,7 +3144,7 @@ call_simple_config_write_default
"\n";
struct error *e = NULL;
- char *filename = simple_config_write_default (hint, prolog, table, &e);
+ char *filename = simple_config_write_default (path_hint, prolog, table, &e);
if (!filename)
{
print_error ("%s", e->message);