degesch: implement /save

Fuck yes. :)
This commit is contained in:
Přemysl Eric Janouch 2015-05-03 19:34:01 +02:00
parent bdad4dce42
commit 72e5aeba58
1 changed files with 82 additions and 87 deletions

169
degesch.c
View File

@ -785,6 +785,59 @@ get_config_boolean (struct app_context *ctx, const char *key)
return item->value.boolean;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
static char *
write_configuration_file (const struct str *data, struct error **e)
{
struct str path;
str_init (&path);
get_xdg_home_dir (&path, "XDG_CONFIG_HOME", ".config");
str_append (&path, "/" PROGRAM_NAME);
if (!mkdir_with_parents (path.str, e))
goto error;
str_append (&path, "/" PROGRAM_NAME ".conf");
FILE *fp = fopen (path.str, "w");
if (!fp)
{
error_set (e, "could not open `%s' for writing: %s",
path.str, strerror (errno));
goto error;
}
errno = 0;
fwrite (data->str, data->len, 1, fp);
fclose (fp);
if (errno)
{
error_set (e, "writing to `%s' failed: %s", path.str, strerror (errno));
goto error;
}
return str_steal (&path);
error:
str_free (&path);
return NULL;
}
static void
serialize_configuration (struct app_context *ctx, struct str *output)
{
str_append (output,
"# " 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"
"# Everything is in UTF-8. Any custom comments will be overwritten.\n"
"\n");
config_item_write (ctx->config.root, true, output);
}
// --- Attributed output -------------------------------------------------------
static struct
@ -3981,6 +4034,33 @@ handle_command_set (struct app_context *ctx, char *arguments)
return result;
}
static bool
handle_command_save (struct app_context *ctx, char *arguments)
{
if (*arguments)
return false;
struct str data;
str_init (&data);
serialize_configuration (ctx, &data);
struct error *e = NULL;
char *filename = write_configuration_file (&data, &e);
str_free (&data);
if (!filename)
{
buffer_send_error (ctx, ctx->global_buffer,
"%s: %s", "Saving configuration failed", e->message);
error_free (e);
}
else
buffer_send_status (ctx, ctx->global_buffer,
"Configuration written to `%s'", filename);
free (filename);
return true;
}
static bool
handle_command_msg (struct app_context *ctx, char *arguments)
{
@ -4211,6 +4291,8 @@ g_command_handlers[] =
"list | clear | move | { close [<number> | <name>] } | <number>" },
{ "set", handle_command_set, "Manage configuration",
"[<option>]" },
{ "save", handle_command_save, "Save configuration",
"" },
{ "msg", handle_command_msg, "Send message to a nick or channel",
"<target> <message>" },
@ -4940,88 +5022,6 @@ load_configuration (struct app_context *ctx)
get_config_integer (ctx, "server.reconnect_delay");
}
static char *
write_configuration_file (const struct str *data, struct error **e)
{
struct str path;
str_init (&path);
get_xdg_home_dir (&path, "XDG_CONFIG_HOME", ".config");
str_append (&path, "/" PROGRAM_NAME);
if (!mkdir_with_parents (path.str, e))
goto error;
str_append (&path, "/" PROGRAM_NAME ".conf");
FILE *fp = fopen (path.str, "w");
if (!fp)
{
error_set (e, "could not open `%s' for writing: %s",
path.str, strerror (errno));
goto error;
}
errno = 0;
fwrite (data->str, data->len, 1, fp);
fclose (fp);
if (errno)
{
error_set (e, "writing to `%s' failed: %s", path.str, strerror (errno));
goto error;
}
return str_steal (&path);
error:
str_free (&path);
return NULL;
}
static void
serialize_configuration (struct app_context *ctx, struct str *output)
{
str_append (output,
"# " 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"
"# Everything is in UTF-8. Any custom comments will be overwritten.\n"
"\n");
config_item_write (ctx->config.root, true, output);
}
static void
write_default_configuration ()
{
// XXX: this is a hack before we remove this awkward functionality
// altogether; the user will want to do this from the user interface
struct app_context ctx = {};
config_init (&ctx.config);
register_config_modules (&ctx);
config_load (&ctx.config, config_item_object ());
struct str data;
str_init (&data);
serialize_configuration (&ctx, &data);
struct error *e = NULL;
char *filename = write_configuration_file (&data, &e);
str_free (&data);
config_free (&ctx.config);
if (!filename)
{
print_error ("%s", e->message);
error_free (e);
exit (EXIT_FAILURE);
}
print_status ("configuration written to `%s'", filename);
free (filename);
}
// --- Main program ------------------------------------------------------------
static void
@ -5050,8 +5050,6 @@ main (int argc, char *argv[])
{ 'd', "debug", NULL, 0, "run in debug mode" },
{ 'h', "help", NULL, 0, "display this help and exit" },
{ 'V', "version", NULL, 0, "output version information and exit" },
{ 'w', "write-default-cfg", NULL, OPT_LONG_ONLY,
"write a default configuration file and exit" },
{ 0, NULL, NULL, 0, NULL }
};
@ -5071,9 +5069,6 @@ main (int argc, char *argv[])
case 'V':
printf (PROGRAM_NAME " " PROGRAM_VERSION "\n");
exit (EXIT_SUCCESS);
case 'w':
write_default_configuration ();
exit (EXIT_SUCCESS);
default:
print_error ("wrong options");
opt_handler_usage (&oh, stderr);