225 lines
5.2 KiB
C
225 lines
5.2 KiB
C
#include <glib.h>
|
|
#include <stdio.h>
|
|
#include <errno.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
|
|
#include "gm-options.h"
|
|
#include "gm-string.h"
|
|
#include "gm-debug.h"
|
|
|
|
extern int errno;
|
|
|
|
#define GM_OPTIONS_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), \
|
|
GM_TYPE_OPTIONS, GmOptionsPrivate))
|
|
|
|
struct _GmOptionsPrivate {
|
|
GHashTable *options;
|
|
gchar *filepath;
|
|
};
|
|
|
|
/* Signals */
|
|
|
|
enum {
|
|
OPTION_CHANGED,
|
|
NUM_SIGNALS
|
|
};
|
|
|
|
static guint options_signals[NUM_SIGNALS] = {0};
|
|
|
|
G_DEFINE_TYPE(GmOptions, gm_options, G_TYPE_OBJECT)
|
|
|
|
static void
|
|
gm_options_finalize(GObject *object) {
|
|
GmOptions *options = GM_OPTIONS(object);
|
|
|
|
g_hash_table_destroy(options->priv->options);
|
|
g_free(options->priv->filepath);
|
|
|
|
G_OBJECT_CLASS(gm_options_parent_class)->finalize(object);
|
|
}
|
|
|
|
static void
|
|
gm_options_class_init(GmOptionsClass *klass) {
|
|
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
|
|
|
object_class->finalize = gm_options_finalize;
|
|
|
|
options_signals[OPTION_CHANGED] =
|
|
g_signal_new("option_changed",
|
|
G_OBJECT_CLASS_TYPE(object_class),
|
|
G_SIGNAL_RUN_LAST,
|
|
G_STRUCT_OFFSET(GmOptionsClass, option_changed),
|
|
NULL, NULL,
|
|
g_cclosure_marshal_VOID__STRING,
|
|
G_TYPE_NONE,
|
|
1,
|
|
G_TYPE_STRING);
|
|
|
|
g_type_class_add_private(object_class, sizeof(GmOptionsPrivate));
|
|
}
|
|
|
|
static void
|
|
gm_options_init(GmOptions *options) {
|
|
options->priv = GM_OPTIONS_GET_PRIVATE(options);
|
|
options->priv->options = g_hash_table_new_full(g_str_hash, g_str_equal,
|
|
g_free, g_free);
|
|
options->priv->filepath = NULL;
|
|
}
|
|
|
|
GmOptions *
|
|
gm_options_new(void) {
|
|
GmOptions *options = GM_OPTIONS(g_object_new(GM_TYPE_OPTIONS, NULL));
|
|
|
|
return options;
|
|
}
|
|
|
|
void
|
|
gm_options_dup_option(gchar *key, gchar *value, GmOptions *copy) {
|
|
gm_options_set(copy, key, value);
|
|
}
|
|
|
|
GmOptions *
|
|
gm_options_dup(GmOptions *source) {
|
|
GmOptions *copy = gm_options_new();
|
|
|
|
g_hash_table_foreach(source->priv->options, (GHFunc)gm_options_dup_option,
|
|
copy);
|
|
|
|
return copy;
|
|
}
|
|
|
|
// Adds an option to opt, even if key already exists
|
|
void
|
|
gm_options_set(GmOptions * options, gchar const *key, gchar const *value) {
|
|
gchar *trimmed = gm_string_trim(key);
|
|
gchar *lookup = g_hash_table_lookup(options->priv->options, trimmed);
|
|
gboolean changed = lookup != NULL && lookup != value;
|
|
|
|
if (lookup != value) {
|
|
g_hash_table_insert(options->priv->options, g_strdup(trimmed),
|
|
g_strdup(value));
|
|
}
|
|
|
|
if (changed) {
|
|
g_signal_emit(options, options_signals[OPTION_CHANGED], 0, trimmed);
|
|
}
|
|
|
|
g_free(trimmed);
|
|
}
|
|
|
|
gchar const *
|
|
gm_options_get(GmOptions *options, gchar const *key) {
|
|
return g_hash_table_lookup(options->priv->options, key);
|
|
}
|
|
|
|
void
|
|
gm_options_set_int(GmOptions *options, gchar const *key, int value) {
|
|
gchar val[15];
|
|
|
|
g_snprintf((gchar *) &val, 15, "%d", value);
|
|
gm_options_set(options, key, (gchar const *)val);
|
|
}
|
|
|
|
int
|
|
gm_options_get_int(GmOptions *options, gchar const *key) {
|
|
gchar const *val = gm_options_get(options, key);
|
|
int ret;
|
|
|
|
if (val && gm_string_to_int(val, &ret)) {
|
|
return ret;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
void
|
|
gm_options_remove(GmOptions *options, gchar const *key) {
|
|
g_hash_table_remove(options->priv->options, key);
|
|
}
|
|
|
|
void
|
|
gm_options_save_value(gchar *key, gchar *value, FILE *f) {
|
|
gm_debug_msg(DEBUG_DEFAULT, "GmOptions.SaveValue: saving %s, %s", key,
|
|
value);
|
|
fprintf(f, "%s=%s\n", key, value);
|
|
}
|
|
|
|
void
|
|
gm_options_save(GmOptions *options) {
|
|
FILE *f;
|
|
|
|
if (options->priv->filepath == NULL) {
|
|
return;
|
|
}
|
|
|
|
f = fopen(options->priv->filepath, "w");
|
|
|
|
gm_debug_msg(DEBUG_DEFAULT, "GmOptions.save: saving options (%s)!",
|
|
options->priv->filepath);
|
|
|
|
if (f) {
|
|
g_hash_table_foreach(options->priv->options,
|
|
(GHFunc)gm_options_save_value, f);
|
|
|
|
fclose(f);
|
|
chmod(options->priv->filepath, 0660);
|
|
} else {
|
|
gm_debug_msg(DEBUG_DEFAULT, "GmOptions.save: couldn't open option "
|
|
"file for saving: %s", strerror(errno));
|
|
}
|
|
}
|
|
|
|
void
|
|
gm_options_save_as(GmOptions *options, gchar const *filename) {
|
|
g_free(options->priv->filepath);
|
|
options->priv->filepath = g_strdup(filename);
|
|
|
|
gm_options_save(options);
|
|
}
|
|
|
|
void
|
|
gm_options_load(GmOptions *options, const char *filename) {
|
|
FILE *f;
|
|
gchar **keyvalue, line[1024];
|
|
int i;
|
|
|
|
gm_debug_msg(DEBUG_DEFAULT, "GmOptions.load: loading options (%s)!",
|
|
filename);
|
|
|
|
if ((f = fopen(filename, "r")) != NULL) {
|
|
i = 0;
|
|
while (fgets((char *) &line, 1024 - 1, f) != NULL) {
|
|
line[strlen((char *) &line) - 1] = '\0';
|
|
i++;
|
|
|
|
if (strlen(line) != 0) {
|
|
// Empty lines, we don't need to process those
|
|
keyvalue = g_strsplit(line, "=", 2);
|
|
// This will return at least 1 element, at most 2, we need 2
|
|
if (strncmp(keyvalue[0], "#", 1) != 0) {
|
|
// Commented lines, well ignore them too
|
|
if (keyvalue[1] != NULL) {
|
|
gm_debug_msg(DEBUG_DEFAULT, "GmOptions.load: "
|
|
"adding %s, %s", keyvalue[0], keyvalue[1]);
|
|
gm_options_set(options, keyvalue[0], keyvalue[1]);
|
|
} else {
|
|
gm_debug_msg(DEBUG_DEFAULT, "GmOptions.load: wrong "
|
|
"syntax of options line in %s line %d",
|
|
filename, i);
|
|
}
|
|
}
|
|
|
|
g_strfreev(keyvalue);
|
|
}
|
|
}
|
|
|
|
fclose(f);
|
|
} else {
|
|
gm_debug_msg(DEBUG_DEFAULT, "GmOptions.load: could not retrieve "
|
|
"contents of file %s (%s)", filename, strerror(errno));
|
|
}
|
|
|
|
g_free(options->priv->filepath);
|
|
options->priv->filepath = g_strdup(filename);
|
|
}
|