grim/guifications3

Parents 8f1208fb3b1c
Children 2aead0d89978
implement the preference uri command line and environment variable handling. This hasn't been tested yet, unit tests to come soon.

refs #69
--- a/gflib/gflib/gf_preferences.c Wed Dec 09 17:48:51 2009 -0600
+++ b/gflib/gflib/gf_preferences.c Wed Dec 09 20:23:28 2009 -0600
@@ -18,38 +18,213 @@
#include <gflib/gf_preferences.h>
#include <gflib/gf_filesystem.h>
+#include <gflib/gf_log.h>
#include <gflib/gf_preference_engine_null.h>
#include <gflib/gf_preference_engine_xml.h>
#include <string.h>
+#define PREFS_URI_REGEX \
+ "^([A-Za-z][A-Z-a-z0-9]*):((([A-Za-z].*)=(.*))(,([A-Za-z].*)=(.*)))*$"
+
/******************************************************************************
* Globals
*****************************************************************************/
static GfPreferenceEngine *root = NULL;
/******************************************************************************
+ * Helpers
+ *****************************************************************************/
+static GfPreferenceEngine *
+gf_preferences_create_default_engine(const gchar *appname) {
+ GfPreferenceEngine *engine = NULL;
+
+ if(appname) {
+ gchar *gf_dir = NULL, *base = NULL, *filename = NULL;
+
+ gf_dir = gf_fs_user_settings_dir();
+ base = g_path_get_basename(appname);
+
+ filename = g_build_filename(gf_dir, base, "prefs.xml", NULL);
+
+ g_free(gf_dir);
+ g_free(base);
+
+ engine = gf_preference_engine_xml_new(filename);
+ } else {
+ engine = gf_preference_engine_null_new();
+ }
+
+ return engine;
+}
+
+/* This big ass basturd takes a uri in the form of:
+ *
+ * GTypeName:GParamName=Value,GParamName,Value
+ *
+ * and creates an object out of it. This might be worth splitting out at some
+ * point. But until then, it's fine where it is. But if it were to be split
+ * out, it should go into gf_object.[ch] and have it's log messages cleaned up.
+ */
+static GfPreferenceEngine *
+gf_preferences_create_engine_from_uri(const gchar *uri) {
+ GfPreferenceEngine *engine = NULL;
+ GError *error = NULL;
+ GList *gc = NULL, *l = NULL;
+ GMatchInfo *match_info = NULL;
+ GParameter *params = NULL;
+ GRegex *regex = NULL;
+ GType type = G_TYPE_INVALID;
+ gchar *type_name = NULL;
+ guint n_params = 0;
+ gint matches = 0;
+
+ regex = g_regex_new(PREFS_URI_REGEX, 0, 0, &error);
+
+ if(!g_regex_match(regex, uri, 0, &match_info)) {
+ g_regex_unref(regex);
+
+ gf_log_warning("GfPreferences",
+ "Could not parse preference uri: '%s'\n"
+ "Falling back to the default preference engine.\n",
+ uri);
+
+ return NULL;
+ }
+
+ /* we have the match_info now, so kill the regex */
+ g_regex_unref(regex);
+
+ /* the type name is in position 1, so grab it and see if the type even
+ * exists.
+ */
+ type_name = g_match_info_fetch(match_info, 1);
+ type = g_type_from_name(type_name);
+
+ if(type == G_TYPE_INVALID) {
+ g_match_info_free(match_info);
+
+ gf_log_warning("GfPreferences",
+ "Could not find the type information for preference "
+ "engine '%s'\n"
+ "Falling back to the default preference engine.\n",
+ type_name);
+
+ g_free(type_name);
+
+ return NULL;
+ }
+
+ /* now dig through the given params and build the GParameterArray */
+ if((matches = g_match_info_get_match_count(match_info)) > 1) {
+ GObjectClass *klass = g_type_class_ref(type);
+ guint cur = 0;
+
+ /* we ignore the first two matches (the engine and the full param
+ * string. Then our params are grouped in threes: name=value, name,
+ * and value. So our number of params is (matches - 2) / 3
+ */
+ n_params = (guint)((matches - 2) / 3);
+
+ /* now allocate params */
+ params = g_new0(GParameter, n_params + 1);
+
+ for(cur = 0; cur < n_params; cur++) {
+ GParamSpec *pspec = NULL;
+ gchar *name = NULL, *value = NULL;
+ gint index = 0;
+
+ /* we multiple by 3 to get to the group, and add two to actually
+ * get to the data.
+ */
+ index = (cur * 3) + 2;
+
+ /* grab the name and see if the parameter exists and that we can
+ * handle it's type. If we can't do either, log a warning and
+ * continue on.
+ */
+ name = g_match_info_fetch(match_info, index + 1);
+ pspec = g_object_class_find_property(klass, name);
+
+ if(!pspec) {
+ gf_log_warning("GfPreferences",
+ "Preference engine %s does not have a property "
+ "named '%s'.\n",
+ type_name, name);
+
+ g_free(name);
+
+ continue;
+ }
+
+ switch(pspec->value_type) {
+ case G_TYPE_STRING:
+ break;
+ default:
+ gf_log_warning("GfPreference",
+ "Don't know how to handle property '%s' "
+ "with type '%s' for engine '%s'.\n",
+ name, g_type_name(pspec->value_type),
+ type_name);
+
+ g_free(name);
+
+ continue;
+ }
+
+ /* we know the property exists now, so set it in the GParameter and
+ * add the name to gc
+ */
+ params[cur].name = name;
+ gc = g_list_prepend(gc, name);
+
+ /* set the GValue in the GParameter */
+ value = g_match_info_fetch(match_info, index + 2);
+
+ g_value_init(&params[cur].value, G_TYPE_STRING);
+ g_value_take_string(&params[cur].value, value);
+ }
+
+ g_type_class_unref(klass);
+ }
+
+ engine = g_object_newv(type, n_params, params);
+
+ /* cleanup time! */
+ for(l = gc; l; l = l->next)
+ g_free(l->data);
+ g_list_free(gc);
+
+ g_match_info_free(match_info);
+
+ /* we free the type_name down here so we can use it in the error messages
+ * during all the fun above.
+ */
+ g_free(type_name);
+
+ return engine;
+}
+
+/******************************************************************************
* Private API
*****************************************************************************/
void
gf_preferences_init(const gchar *appname, const gchar *uri) {
- if(!uri) {
- if(appname) {
- gchar *gf_dir = NULL, *base = NULL, *filename = NULL;
+ GfPreferenceEngine *engine = NULL;
+ const gchar *real_uri = NULL;
- gf_dir = gf_fs_user_settings_dir();
- base = g_path_get_basename(appname);
-
- filename = g_build_filename(gf_dir, base, "prefs.xml", NULL);
+ /* if the uri was given on the command line, use it. Otherwise, try the
+ * environment variable.
+ */
+ real_uri = (uri) ? uri : g_getenv("GF_PREFS_URI");
- g_free(gf_dir);
- g_free(base);
+ if(real_uri)
+ engine = gf_preferences_create_engine_from_uri(real_uri);
- root = gf_preference_engine_xml_new(filename);
- } else {
- root = gf_preference_engine_null_new();
- }
- }
+ if(!engine)
+ engine = gf_preferences_create_default_engine(appname);
+
+ root = engine;
}
void