/* GConf
* Copyright (C) 1999, 2000, 2002 Red Hat Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "gconf-value.h"
#include "gconf-error.h"
#include "gconf-schema.h"
#include "gconf-internals.h"
#include <errno.h>
#include <string.h>
#include <stdlib.h>
typedef struct {
GConfValueType type;
union {
gchar* string_data;
gint int_data;
gboolean bool_data;
gdouble float_data;
GConfSchema* schema_data;
struct {
GConfValueType type;
GSList* list;
} list_data;
struct {
GConfValue* car;
GConfValue* cdr;
} pair_data;
} d;
} GConfRealValue;
#define REAL_VALUE(x) ((GConfRealValue*)(x))
static void
set_string(gchar** dest, const gchar* src)
{
if (*dest != NULL)
g_free(*dest);
*dest = src ? g_strdup(src) : NULL;
}
/*
* Values
*/
GConfValue*
gconf_value_new(GConfValueType type)
{
GConfValue* value;
static gboolean initted = FALSE;
g_return_val_if_fail(GCONF_VALUE_TYPE_VALID(type), NULL);
if (!initted)
{
_gconf_init_i18n ();
initted = TRUE;
}
value = (GConfValue*) g_slice_new0 (GConfRealValue);
value->type = type;
/* the g_new0() is important: sets list type to invalid, NULLs all
* pointers
*/
return value;
}
GConfValue*
gconf_value_new_from_string(GConfValueType type, const gchar* value_str,
GError** err)
{
GConfValue* value;
g_return_val_if_fail (type != GCONF_VALUE_LIST, NULL);
g_return_val_if_fail (type != GCONF_VALUE_PAIR, NULL);
value = gconf_value_new(type);
switch (type)
{
case GCONF_VALUE_INT:
{
char* endptr = NULL;
glong result;
errno = 0;
result = strtol(value_str, &endptr, 10);
if (endptr == value_str)
{
if (err)
*err = gconf_error_new(GCONF_ERROR_PARSE_ERROR,
_("Didn't understand `%s' (expected integer)"),
value_str);
gconf_value_free(value);
value = NULL;
}
else if (errno == ERANGE)
{
if (err)
*err = gconf_error_new(GCONF_ERROR_PARSE_ERROR,
_("Integer `%s' is too large or small"),
value_str);
gconf_value_free(value);
value = NULL;
}
else
gconf_value_set_int(value, result);
}
break;
case GCONF_VALUE_FLOAT:
{
double num;
if (gconf_string_to_double(value_str, &num))
{
gconf_value_set_float(value, num);
}
else
{
if (err)
*err = gconf_error_new(GCONF_ERROR_PARSE_ERROR,
_("Didn't understand `%s' (expected real number)"),
value_str);
gconf_value_free(value);
value = NULL;
}
}
break;
case GCONF_VALUE_STRING:
if (!g_utf8_validate (value_str, -1, NULL))
{
g_set_error (err, GCONF_ERROR,
GCONF_ERROR_PARSE_ERROR,
_("Text contains invalid UTF-8"));
gconf_value_free(value);
value = NULL;
}
else
{
gconf_value_set_string(value, value_str);
}
break;
case GCONF_VALUE_BOOL:
switch (*value_str)
{
case 't':
case 'T':
case '1':
case 'y':
case 'Y':
gconf_value_set_bool(value, TRUE);
break;
case 'f':
case 'F':
case '0':
case 'n':
case 'N':
gconf_value_set_bool(value, FALSE);
break;
default:
if (err)
*err = gconf_error_new(GCONF_ERROR_PARSE_ERROR,
_("Didn't understand `%s' (expected true or false)"),
value_str);
gconf_value_free(value);
value = NULL;
break;
}
break;
case GCONF_VALUE_LIST:
case GCONF_VALUE_PAIR:
default:
g_assert_not_reached();
break;
}
return value;
}
static char *
escape_string(const char *str, const char *escaped_chars)
{
gint i, j, len;
gchar* ret;
len = 0;
for (i = 0; str[i] != '\0'; i++)
{
if (strchr(escaped_chars, str[i]) != NULL ||
str[i] == '\\')
len++;
len++;
}
ret = g_malloc(len + 1);
j = 0;
for (i = 0; str[i] != '\0'; i++)
{
if (strchr(escaped_chars, str[i]) != NULL ||
str[i] == '\\')
{
ret[j++] = '\\';
}
ret[j++] = str[i];
}
ret[j++] = '\0';
return ret;
}
GConfValue*
gconf_value_new_list_from_string(GConfValueType list_type,
const gchar* str,
GError** err)
{
int i, len;
gboolean escaped, pending_chars;
GString *string;
GConfValue* value;
GSList *list;
g_return_val_if_fail(list_type != GCONF_VALUE_LIST, NULL);
g_return_val_if_fail(list_type != GCONF_VALUE_PAIR, NULL);
if (!g_utf8_validate (str, -1, NULL))
{
g_set_error (err, GCONF_ERROR,
GCONF_ERROR_PARSE_ERROR,
_("Text contains invalid UTF-8"));
return NULL;
}
if (str[0] != '[')
{
if (err)
*err = gconf_error_new(GCONF_ERROR_PARSE_ERROR,
_("Didn't understand `%s' (list must start with a '[')"),
str);
return NULL;
}
len = strlen(str);
/* Note: by now len is sure to be 1 or larger, so len-1 will never be
* negative */
if (str[len-1] != ']')
{
if (err)
*err = gconf_error_new(GCONF_ERROR_PARSE_ERROR,
_("Didn't understand `%s' (list must end with a ']')"),
str);
return NULL;
}
if (strstr(str, "[]"))
{
value = gconf_value_new(GCONF_VALUE_LIST);
gconf_value_set_list_type(value, list_type);
return value;
}
escaped = FALSE;
pending_chars = FALSE;
list = NULL;
string = g_string_new(NULL);
for (i = 1; str[i] != '\0'; i++)
{
if ( ! escaped &&
(str[i] == ',' ||
str[i] == ']'))
{
GConfValue* val;
val = gconf_value_new_from_string(list_type, string->str, err);
if (err && *err != NULL)
{
/* Free values so far */
g_slist_foreach(list, (GFunc)gconf_value_free, NULL);
g_slist_free(list);
g_string_free(string, TRUE);
return NULL;
}
g_string_assign(string, "");
list = g_slist_prepend(list, val);
if (str[i] == ']' &&
i != len-1)
{
/* Free values so far */
g_slist_foreach(list, (GFunc)gconf_value_free, NULL);
g_slist_free(list);
g_string_free(string, TRUE);
if (err)
*err = gconf_error_new(GCONF_ERROR_PARSE_ERROR,
_("Didn't understand `%s' (extra unescaped ']' found inside list)"),
str);
return NULL;
}
pending_chars = FALSE;
}
else if ( ! escaped && str[i] == '\\')
{
escaped = TRUE;
pending_chars = TRUE;
}
else
{
g_string_append_c(string, str[i]);
escaped = FALSE;
pending_chars = TRUE;
}
}
g_string_free(string, TRUE);
if (pending_chars)
{
/* Free values so far */
g_slist_foreach(list, (GFunc)gconf_value_free, NULL);
g_slist_free(list);
g_string_free(string, TRUE);
if (err)
*err = gconf_error_new(GCONF_ERROR_PARSE_ERROR,
_("Didn't understand `%s' (extra trailing characters)"),
str);
return NULL;
}
/* inverse list as we were prepending to it */
list = g_slist_reverse(list);
value = gconf_value_new(GCONF_VALUE_LIST);
gconf_value_set_list_type(value, list_type);
gconf_value_set_list_nocopy(value, list);
return value;
}
GConfValue*
gconf_value_new_pair_from_string(GConfValueType car_type,
GConfValueType cdr_type,
const gchar* str,
GError** err)
{
int i, len;
int elem;
gboolean escaped, pending_chars;
GString *string;
GConfValue* value;
GConfValue* car;
GConfValue* cdr;
g_return_val_if_fail(car_type != GCONF_VALUE_LIST, NULL);
g_return_val_if_fail(car_type != GCONF_VALUE_PAIR, NULL);
g_return_val_if_fail(cdr_type != GCONF_VALUE_LIST, NULL);
g_return_val_if_fail(cdr_type != GCONF_VALUE_PAIR, NULL);
if (!g_utf8_validate (str, -1, NULL))
{
g_set_error (err, GCONF_ERROR,
GCONF_ERROR_PARSE_ERROR,
_("Text contains invalid UTF-8"));
return NULL;
}
if (str[0] != '(')
{
if (err)
*err = gconf_error_new(GCONF_ERROR_PARSE_ERROR,
_("Didn't understand `%s' (pair must start with a '(')"),
str);
return NULL;
}
len = strlen(str);
/* Note: by now len is sure to be 1 or larger, so len-1 will never be
* negative */
if (str[len-1] != ')')
{
if (err)
*err = gconf_error_new(GCONF_ERROR_PARSE_ERROR,
_("Didn't understand `%s' (pair must end with a ')')"),
str);
return NULL;
}
escaped = FALSE;
pending_chars = FALSE;
car = cdr = NULL;
string = g_string_new(NULL);
elem = 0;
for (i = 1; str[i] != '\0'; i++)
{
if ( ! escaped &&
(str[i] == ',' ||
str[i] == ')'))
{
if ((str[i] == ')' && elem != 1) ||
(elem > 1))
{
/* Free values so far */
if (car)
gconf_value_free(car);
if (cdr)
gconf_value_free(cdr);
g_string_free(string, TRUE);
if (err)
*err = gconf_error_new(GCONF_ERROR_PARSE_ERROR,
_("Didn't understand `%s' (wrong number of elements)"),
str);
return NULL;
}
if (elem == 0)
car = gconf_value_new_from_string(car_type, string->str, err);
else if (elem == 1)
cdr = gconf_value_new_from_string(cdr_type, string->str, err);
elem ++;
if (err && *err != NULL)
{
/* Free values so far */
if (car)
gconf_value_free(car);
if (cdr)
gconf_value_free(cdr);
g_string_free(string, TRUE);
return NULL;
}
g_string_assign(string, "");
if (str[i] == ')' &&
i != len-1)
{
/* Free values so far */
if (car)
gconf_value_free(car);
if (cdr)
gconf_value_free(cdr);
g_string_free(string, TRUE);
if (err)
*err = gconf_error_new(GCONF_ERROR_PARSE_ERROR,
_("Didn't understand `%s' (extra unescaped ')' found inside pair)"),
str);
return NULL;
}
pending_chars = FALSE;
}
else if ( ! escaped && str[i] == '\\')
{
escaped = TRUE;
pending_chars = TRUE;
}
else
{
g_string_append_c(string, str[i]);
escaped = FALSE;
pending_chars = TRUE;
}
}
g_string_free(string, TRUE);
if (pending_chars)
{
/* Free values so far */
if (car)
gconf_value_free(car);
if (cdr)
gconf_value_free(cdr);
if (err)
*err = gconf_error_new(GCONF_ERROR_PARSE_ERROR,
_("Didn't understand `%s' (extra trailing characters)"),
str);
return NULL;
}
if (elem != 2)
{
/* Free values so far */
if (car)
gconf_value_free(car);
if (cdr)
gconf_value_free(cdr);
if (err)
*err = gconf_error_new(GCONF_ERROR_PARSE_ERROR,
_("Didn't understand `%s' (wrong number of elements)"),
str);
return NULL;
}
value = gconf_value_new(GCONF_VALUE_PAIR);
gconf_value_set_car_nocopy(value, car);
gconf_value_set_cdr_nocopy(value, cdr);
return value;
}
gchar*
gconf_value_to_string(const GConfValue* value)
{
/* These strings shouldn't be translated; they're primarily
intended for machines to read, not humans, though I do
use them in some debug spew
*/
gchar* retval = NULL;
switch (value->type)
{
case GCONF_VALUE_INT:
retval = g_strdup_printf("%d", gconf_value_get_int(value));
break;
case GCONF_VALUE_FLOAT:
retval = gconf_double_to_string(gconf_value_get_float(value));
break;
case GCONF_VALUE_STRING:
retval = g_strdup(gconf_value_get_string(value));
break;
case GCONF_VALUE_BOOL:
retval = gconf_value_get_bool(value) ? g_strdup("true") : g_strdup("false");
break;
case GCONF_VALUE_LIST:
{
GSList* list;
list = gconf_value_get_list(value);
if (list == NULL)
retval = g_strdup("[]");
else
{
gchar* buf = NULL;
guint bufsize = 64;
guint cur = 0;
g_assert(list != NULL);
buf = g_malloc(bufsize+3); /* my +3 superstition */
buf[0] = '[';
++cur;
g_assert(cur < bufsize);
while (list != NULL)
{
gchar* tmp;
gchar* elem;
guint len;
tmp = gconf_value_to_string((GConfValue*)list->data);
g_assert(tmp != NULL);
elem = escape_string(tmp, ",]");
g_free(tmp);
len = strlen(elem);
if ((cur + len + 2) >= bufsize) /* +2 for '\0' and comma */
{
bufsize = MAX(bufsize*2, bufsize+len+4);
buf = g_realloc(buf, bufsize+3);
}
g_assert(cur < bufsize);
strcpy(&buf[cur], elem);
cur += len;
g_assert(cur < bufsize);
g_free(elem);
buf[cur] = ',';
++cur;
g_assert(cur < bufsize);
list = g_slist_next(list);
}
g_assert(cur < bufsize);
buf[cur-1] = ']'; /* overwrites last comma */
buf[cur] = '\0';
retval = buf;
}
}
break;
case GCONF_VALUE_PAIR:
{
gchar* tmp;
gchar* car;
gchar* cdr;
if (gconf_value_get_car (value))
tmp = gconf_value_to_string(gconf_value_get_car(value));
else
tmp = g_strdup ("nil");
car = escape_string(tmp, ",)");
g_free(tmp);
if (gconf_value_get_cdr (value))
tmp = gconf_value_to_string(gconf_value_get_cdr(value));
else
tmp = g_strdup ("nil");
cdr = escape_string(tmp, ",)");
g_free(tmp);
retval = g_strdup_printf("(%s,%s)", car, cdr);
g_free(car);
g_free(cdr);
}
break;
/* These remaining shouldn't really be used outside of debug spew... */
case GCONF_VALUE_INVALID:
retval = g_strdup("Invalid");
break;
case GCONF_VALUE_SCHEMA:
{
const gchar* locale;
const gchar* type;
const gchar* list_type;
const gchar* car_type;
const gchar* cdr_type;
locale = gconf_schema_get_locale(gconf_value_get_schema(value));
type = gconf_value_type_to_string(gconf_schema_get_type(gconf_value_get_schema(value)));
list_type = gconf_value_type_to_string(gconf_schema_get_list_type(gconf_value_get_schema(value)));
car_type = gconf_value_type_to_string(gconf_schema_get_car_type(gconf_value_get_schema(value)));
cdr_type = gconf_value_type_to_string(gconf_schema_get_cdr_type(gconf_value_get_schema(value)));
retval = g_strdup_printf("Schema (type: `%s' list_type: '%s' "
"car_type: '%s' cdr_type: '%s' locale: `%s')",
type, list_type, car_type, cdr_type,
locale ? locale : "(null)");
}
break;
default:
g_assert_not_reached();
break;
}
return retval;
}
static GSList*
copy_value_list(GSList* list)
{
GSList* copy = NULL;
GSList* tmp = list;
while (tmp != NULL)
{
copy = g_slist_prepend(copy, gconf_value_copy(tmp->data));
tmp = g_slist_next(tmp);
}
copy = g_slist_reverse(copy);
return copy;
}
GConfValue*
gconf_value_copy (const GConfValue* src)
{
GConfRealValue *dest;
GConfRealValue *real;
g_return_val_if_fail(src != NULL, NULL);
real = REAL_VALUE (src);
dest = REAL_VALUE (gconf_value_new (src->type));
switch (real->type)
{
case GCONF_VALUE_INT:
case GCONF_VALUE_FLOAT:
case GCONF_VALUE_BOOL:
case GCONF_VALUE_INVALID:
dest->d = real->d;
break;
case GCONF_VALUE_STRING:
set_string(&dest->d.string_data, real->d.string_data);
break;
case GCONF_VALUE_SCHEMA:
if (real->d.schema_data)
dest->d.schema_data = gconf_schema_copy(real->d.schema_data);
else
dest->d.schema_data = NULL;
break;
case GCONF_VALUE_LIST:
{
GSList* copy;
copy = copy_value_list(real->d.list_data.list);
dest->d.list_data.list = copy;
dest->d.list_data.type = real->d.list_data.type;
}
break;
case GCONF_VALUE_PAIR:
if (real->d.pair_data.car)
dest->d.pair_data.car = gconf_value_copy(real->d.pair_data.car);
else
dest->d.pair_data.car = NULL;
if (real->d.pair_data.cdr)
dest->d.pair_data.cdr = gconf_value_copy(real->d.pair_data.cdr);
else
dest->d.pair_data.cdr = NULL;
break;
default:
g_assert_not_reached();
}
return (GConfValue*) dest;
}
static void
gconf_value_free_list(GConfValue* value)
{
GSList* tmp;
GConfRealValue *real;
g_return_if_fail(value != NULL);
g_return_if_fail(value->type == GCONF_VALUE_LIST);
real = REAL_VALUE (value);
tmp = real->d.list_data.list;
while (tmp != NULL)
{
gconf_value_free(tmp->data);
tmp = g_slist_next(tmp);
}
g_slist_free(real->d.list_data.list);
real->d.list_data.list = NULL;
}
void
gconf_value_free(GConfValue* value)
{
GConfRealValue *real;
g_return_if_fail(value != NULL);
real = REAL_VALUE (value);
switch (real->type)
{
case GCONF_VALUE_STRING:
if (real->d.string_data != NULL)
g_free(real->d.string_data);
break;
case GCONF_VALUE_SCHEMA:
if (real->d.schema_data != NULL)
gconf_schema_free(real->d.schema_data);
break;
case GCONF_VALUE_LIST:
gconf_value_free_list(value);
break;
case GCONF_VALUE_PAIR:
if (real->d.pair_data.car != NULL)
gconf_value_free(real->d.pair_data.car);
if (real->d.pair_data.cdr != NULL)
gconf_value_free(real->d.pair_data.cdr);
break;
default:
break;
}
g_slice_free(GConfRealValue, real);
}
const char*
gconf_value_get_string (const GConfValue *value)
{
g_return_val_if_fail (value != NULL, NULL);
g_return_val_if_fail (value->type == GCONF_VALUE_STRING, NULL);
return REAL_VALUE (value)->d.string_data;
}
char*
gconf_value_steal_string (GConfValue *value)
{
char *string;
GConfRealValue *real;
g_return_val_if_fail (value != NULL, NULL);
g_return_val_if_fail (value->type == GCONF_VALUE_STRING, NULL);
real = REAL_VALUE (value);
string = real->d.string_data;
real->d.string_data = NULL;
return string;
}
int
gconf_value_get_int (const GConfValue *value)
{
g_return_val_if_fail (value != NULL, 0);
g_return_val_if_fail (value->type == GCONF_VALUE_INT, 0);
return REAL_VALUE (value)->d.int_data;
}
double
gconf_value_get_float (const GConfValue *value)
{
g_return_val_if_fail (value != NULL, 0.0);
g_return_val_if_fail (value->type == GCONF_VALUE_FLOAT, 0.0);
return REAL_VALUE (value)->d.float_data;
}
GConfValueType
gconf_value_get_list_type (const GConfValue *value)
{
g_return_val_if_fail (value != NULL, GCONF_VALUE_INVALID);
g_return_val_if_fail (value->type == GCONF_VALUE_LIST, GCONF_VALUE_INVALID);
return REAL_VALUE (value)->d.list_data.type;
}
GSList*
gconf_value_get_list (const GConfValue *value)
{
g_return_val_if_fail (value != NULL, NULL);
g_return_val_if_fail (value->type == GCONF_VALUE_LIST, NULL);
return REAL_VALUE (value)->d.list_data.list;
}
GSList*
gconf_value_steal_list (GConfValue *value)
{
GSList *list;
GConfRealValue *real;
g_return_val_if_fail (value != NULL, NULL);
g_return_val_if_fail (value->type == GCONF_VALUE_LIST, NULL);
real = REAL_VALUE (value);
list = real->d.list_data.list;
real->d.list_data.list = NULL;
return list;
}
GConfValue*
gconf_value_get_car (const GConfValue *value)
{
g_return_val_if_fail (value != NULL, NULL);
g_return_val_if_fail (value->type == GCONF_VALUE_PAIR, NULL);
return REAL_VALUE (value)->d.pair_data.car;
}
GConfValue*
gconf_value_get_cdr (const GConfValue *value)
{
g_return_val_if_fail (value != NULL, NULL);
g_return_val_if_fail (value->type == GCONF_VALUE_PAIR, NULL);
return REAL_VALUE (value)->d.pair_data.cdr;
}
gboolean
gconf_value_get_bool (const GConfValue *value)
{
g_return_val_if_fail (value != NULL, FALSE);
g_return_val_if_fail (value->type == GCONF_VALUE_BOOL, FALSE);
return REAL_VALUE (value)->d.bool_data;
}
GConfSchema*
gconf_value_get_schema (const GConfValue *value)
{
g_return_val_if_fail (value != NULL, NULL);
g_return_val_if_fail (value->type == GCONF_VALUE_SCHEMA, NULL);
return REAL_VALUE (value)->d.schema_data;
}
GConfSchema*
gconf_value_steal_schema (GConfValue *value)
{
GConfSchema *schema;
GConfRealValue *real;
g_return_val_if_fail (value != NULL, NULL);
g_return_val_if_fail (value->type == GCONF_VALUE_SCHEMA, NULL);
real = REAL_VALUE (value);
schema = real->d.schema_data;
real->d.schema_data = NULL;
return schema;
}
void
gconf_value_set_int(GConfValue* value, gint the_int)
{
g_return_if_fail(value != NULL);
g_return_if_fail(value->type == GCONF_VALUE_INT);
REAL_VALUE (value)->d.int_data = the_int;
}
void
gconf_value_set_string(GConfValue* value, const gchar* the_str)
{
gconf_value_set_string_nocopy (value,
g_strdup (the_str));
}
void
gconf_value_set_string_nocopy (GConfValue *value,
char *str)
{
GConfRealValue *real;
g_return_if_fail(value != NULL);
g_return_if_fail(value->type == GCONF_VALUE_STRING);
real = REAL_VALUE (value);
g_free (real->d.string_data);
real->d.string_data = str;
}
void
gconf_value_set_float(GConfValue* value, gdouble the_float)
{
g_return_if_fail(value != NULL);
g_return_if_fail(value->type == GCONF_VALUE_FLOAT);
REAL_VALUE (value)->d.float_data = the_float;
}
void
gconf_value_set_bool(GConfValue* value, gboolean the_bool)
{
g_return_if_fail(value != NULL);
g_return_if_fail(value->type == GCONF_VALUE_BOOL);
REAL_VALUE (value)->d.bool_data = the_bool;
}
void
gconf_value_set_schema(GConfValue* value, const GConfSchema* sc)
{
GConfRealValue *real;
g_return_if_fail(value != NULL);
g_return_if_fail(value->type == GCONF_VALUE_SCHEMA);
real = REAL_VALUE (value);
if (real->d.schema_data != NULL)
gconf_schema_free (real->d.schema_data);
real->d.schema_data = gconf_schema_copy (sc);
}
void
gconf_value_set_schema_nocopy(GConfValue* value, GConfSchema* sc)
{
GConfRealValue *real;
g_return_if_fail(value != NULL);
g_return_if_fail(value->type == GCONF_VALUE_SCHEMA);
g_return_if_fail(sc != NULL);
real = REAL_VALUE (value);
if (real->d.schema_data != NULL)
gconf_schema_free (real->d.schema_data);
real->d.schema_data = sc;
}
void
gconf_value_set_car(GConfValue* value, const GConfValue* car)
{
gconf_value_set_car_nocopy(value, gconf_value_copy(car));
}
void
gconf_value_set_car_nocopy(GConfValue* value, GConfValue* car)
{
GConfRealValue *real;
g_return_if_fail(value != NULL);
g_return_if_fail(value->type == GCONF_VALUE_PAIR);
real = REAL_VALUE (value);
if (real->d.pair_data.car != NULL)
gconf_value_free (real->d.pair_data.car);
real->d.pair_data.car = car;
}
void
gconf_value_set_cdr(GConfValue* value, const GConfValue* cdr)
{
gconf_value_set_cdr_nocopy(value, gconf_value_copy(cdr));
}
void
gconf_value_set_cdr_nocopy(GConfValue* value, GConfValue* cdr)
{
GConfRealValue *real;
g_return_if_fail(value != NULL);
g_return_if_fail(value->type == GCONF_VALUE_PAIR);
real = REAL_VALUE (value);
if (real->d.pair_data.cdr != NULL)
gconf_value_free (real->d.pair_data.cdr);
real->d.pair_data.cdr = cdr;
}
void
gconf_value_set_list_type (GConfValue *value,
GConfValueType type)
{
GConfRealValue *real;
g_return_if_fail(value != NULL);
g_return_if_fail(value->type == GCONF_VALUE_LIST);
g_return_if_fail(type != GCONF_VALUE_LIST);
g_return_if_fail(type != GCONF_VALUE_PAIR);
real = REAL_VALUE (value);
/* If the list is non-NULL either we already have the right
* type, or we shouldn't be changing it without deleting
* the list first.
*/
g_return_if_fail (real->d.list_data.list == NULL);
real->d.list_data.type = type;
}
void
gconf_value_set_list_nocopy (GConfValue* value,
GSList* list)
{
GConfRealValue *real;
g_return_if_fail (value != NULL);
g_return_if_fail (value->type == GCONF_VALUE_LIST);
real = REAL_VALUE (value);
g_return_if_fail (real->d.list_data.type != GCONF_VALUE_INVALID);
if (real->d.list_data.list)
gconf_value_free_list (value);
real->d.list_data.list = list;
}
void
gconf_value_set_list (GConfValue* value,
GSList* list)
{
GConfRealValue *real;
g_return_if_fail (value != NULL);
g_return_if_fail (value->type == GCONF_VALUE_LIST);
real = REAL_VALUE (value);
g_return_if_fail (real->d.list_data.type != GCONF_VALUE_INVALID);
g_return_if_fail ((list == NULL) ||
((list->data != NULL) &&
(((GConfValue*)list->data)->type == real->d.list_data.type)));
if (real->d.list_data.list)
gconf_value_free_list (value);
real->d.list_data.list = copy_value_list (list);
}
static int
null_safe_strcmp (const char *lhs,
const char *rhs)
{
if (lhs == NULL && rhs == NULL)
return 0;
else if (lhs == NULL)
return -1;
else if (rhs == NULL)
return 1;
else
return strcmp (lhs, rhs);
}
int
gconf_value_compare (const GConfValue *value_a,
const GConfValue *value_b)
{
g_return_val_if_fail (value_a != NULL, 0);
g_return_val_if_fail (value_b != NULL, 0);
/* Impose arbitrary type ordering, just to keep the
* sort invariants stable.
*/
if (value_a->type < value_b->type)
return -1;
else if (value_a->type > value_b->type)
return 1;
switch (value_a->type)
{
case GCONF_VALUE_INT:
if (gconf_value_get_int (value_a) < gconf_value_get_int (value_b))
return -1;
else if (gconf_value_get_int (value_a) > gconf_value_get_int (value_b))
return 1;
else
return 0;
case GCONF_VALUE_FLOAT:
if (gconf_value_get_float (value_a) < gconf_value_get_float (value_b))
return -1;
else if (gconf_value_get_float (value_a) > gconf_value_get_float (value_b))
return 1;
else
return 0;
case GCONF_VALUE_STRING:
return strcmp (gconf_value_get_string (value_a),
gconf_value_get_string (value_b));
case GCONF_VALUE_BOOL:
if (gconf_value_get_bool (value_a) == gconf_value_get_bool (value_b))
return 0;
/* make TRUE > FALSE to maintain sort invariants */
else if (gconf_value_get_bool (value_a))
return 1;
else
return -1;
case GCONF_VALUE_LIST:
{
GSList *list_a;
GSList *list_b;
list_a = gconf_value_get_list (value_a);
list_b = gconf_value_get_list (value_b);
while (list_a != NULL && list_b != NULL)
{
int result;
result = gconf_value_compare (list_a->data, list_b->data);
if (result != 0)
return result;
list_a = g_slist_next (list_a);
list_b = g_slist_next (list_b);
}
if (list_a)
return 1; /* list_a is longer so "greater" */
else if (list_b)
return -1;
else
return 0;
}
case GCONF_VALUE_PAIR:
{
GConfValue *a_car, *b_car, *a_cdr, *b_cdr;
int result;
a_car = gconf_value_get_car (value_a);
b_car = gconf_value_get_car (value_b);
a_cdr = gconf_value_get_cdr (value_a);
b_cdr = gconf_value_get_cdr (value_b);
if (a_car == NULL && b_car != NULL)
return -1;
else if (a_car != NULL && b_car == NULL)
return 1;
else if (a_car != NULL && b_car != NULL)
{
result = gconf_value_compare (a_car, b_car);
if (result != 0)
return result;
}
if (a_cdr == NULL && b_cdr != NULL)
return -1;
else if (a_cdr != NULL && b_cdr == NULL)
return 1;
else if (a_cdr != NULL && b_cdr != NULL)
{
result = gconf_value_compare (a_cdr, b_cdr);
if (result != 0)
return result;
}
return 0;
}
case GCONF_VALUE_INVALID:
return 0;
case GCONF_VALUE_SCHEMA:
{
const char *locale_a, *locale_b;
GConfValueType type_a, type_b;
GConfValueType list_type_a, list_type_b;
GConfValueType car_type_a, car_type_b;
GConfValueType cdr_type_a, cdr_type_b;
const char *short_desc_a, *short_desc_b;
const char *long_desc_a, *long_desc_b;
int result;
type_a = gconf_schema_get_type (gconf_value_get_schema (value_a));
type_b = gconf_schema_get_type (gconf_value_get_schema (value_b));
if (type_a < type_b)
return -1;
else if (type_a > type_b)
return 1;
short_desc_a = gconf_schema_get_short_desc (gconf_value_get_schema (value_a));
short_desc_b = gconf_schema_get_short_desc (gconf_value_get_schema (value_b));
result = null_safe_strcmp (short_desc_a, short_desc_b);
if (result != 0)
return result;
long_desc_a = gconf_schema_get_long_desc (gconf_value_get_schema (value_a));
long_desc_b = gconf_schema_get_long_desc (gconf_value_get_schema (value_b));
result = null_safe_strcmp (long_desc_a, long_desc_b);
if (result != 0)
return result;
locale_a = gconf_schema_get_locale (gconf_value_get_schema (value_a));
locale_b = gconf_schema_get_locale (gconf_value_get_schema (value_b));
result = null_safe_strcmp (locale_a, locale_b);
if (result != 0)
return result;
if (type_a == GCONF_VALUE_LIST)
{
list_type_a = gconf_schema_get_list_type (gconf_value_get_schema (value_a));
list_type_b = gconf_schema_get_list_type (gconf_value_get_schema (value_b));
if (list_type_a < list_type_b)
return -1;
else if (list_type_a > list_type_b)
return 1;
}
if (type_a == GCONF_VALUE_PAIR)
{
car_type_a = gconf_schema_get_car_type (gconf_value_get_schema (value_a));
car_type_b = gconf_schema_get_car_type (gconf_value_get_schema (value_b));
if (car_type_a < car_type_b)
return -1;
else if (car_type_a > car_type_b)
return 1;
cdr_type_a = gconf_schema_get_cdr_type (gconf_value_get_schema (value_a));
cdr_type_b = gconf_schema_get_cdr_type (gconf_value_get_schema (value_b));
if (cdr_type_a < cdr_type_b)
return -1;
else if (cdr_type_a > cdr_type_b)
return 1;
}
return 0;
}
}
g_assert_not_reached ();
return 0;
}
/*
* GConfMetaInfo
*/
GConfMetaInfo*
gconf_meta_info_new(void)
{
GConfMetaInfo* gcmi;
gcmi = g_new0(GConfMetaInfo, 1);
/* pointers and time are NULL/0 */
return gcmi;
}
void
gconf_meta_info_free(GConfMetaInfo* gcmi)
{
set_string(&gcmi->schema, NULL);
set_string(&gcmi->mod_user, NULL);
g_free(gcmi);
}
const char*
gconf_meta_info_get_schema (GConfMetaInfo *gcmi)
{
g_return_val_if_fail (gcmi != NULL, NULL);
return gcmi->schema;
}
const char*
gconf_meta_info_get_mod_user (GConfMetaInfo *gcmi)
{
g_return_val_if_fail (gcmi != NULL, NULL);
return gcmi->mod_user;
}
GTime
gconf_meta_info_mod_time (GConfMetaInfo *gcmi)
{
g_return_val_if_fail (gcmi != NULL, 0);
return gcmi->mod_time;
}
void
gconf_meta_info_set_schema (GConfMetaInfo* gcmi,
const gchar* schema_name)
{
set_string(&gcmi->schema, schema_name);
}
void
gconf_meta_info_set_mod_user(GConfMetaInfo* gcmi,
const gchar* mod_user)
{
set_string(&gcmi->mod_user, mod_user);
}
void
gconf_meta_info_set_mod_time(GConfMetaInfo* gcmi,
GTime mod_time)
{
gcmi->mod_time = mod_time;
}
/*
* GConfEntry
*/
typedef struct {
char *key;
GConfValue *value;
char *schema_name;
int refcount;
guint is_default : 1;
guint is_writable : 1;
} GConfRealEntry;
#define REAL_ENTRY(x) ((GConfRealEntry*)(x))
GConfEntry*
gconf_entry_new (const char *key,
const GConfValue *val)
{
return gconf_entry_new_nocopy (g_strdup (key),
val ? gconf_value_copy (val) : NULL);
}
GConfEntry*
gconf_entry_new_nocopy (char* key, GConfValue* val)
{
GConfRealEntry* real;
real = g_slice_new (GConfRealEntry);
real->key = key;
real->value = val;
real->schema_name = NULL;
real->is_default = FALSE;
real->is_writable = TRUE;
real->refcount = 1;
return (GConfEntry*) real;
}
void
gconf_entry_ref (GConfEntry *entry)
{
g_return_if_fail (entry != NULL);
REAL_ENTRY (entry)->refcount += 1;
}
void
gconf_entry_unref (GConfEntry *entry)
{
GConfRealEntry *real;
g_return_if_fail (entry != NULL);
g_return_if_fail (REAL_ENTRY (entry)->refcount > 0);
real = REAL_ENTRY (entry);
real->refcount -= 1;
if (real->refcount == 0)
{
g_free (real->key);
if (real->value)
gconf_value_free (real->value);
if (real->schema_name)
g_free (real->schema_name);
g_slice_free (GConfRealEntry, real);
}
}
void
gconf_entry_free (GConfEntry *entry)
{
gconf_entry_unref (entry);
}
GConfEntry*
gconf_entry_copy (const GConfEntry *src)
{
GConfEntry *entry;
GConfRealEntry *real;
entry = gconf_entry_new (REAL_ENTRY (src)->key,
REAL_ENTRY (src)->value);
real = REAL_ENTRY (entry);
real->schema_name = g_strdup (REAL_ENTRY (src)->schema_name);
real->is_default = REAL_ENTRY (src)->is_default;
real->is_writable = REAL_ENTRY (src)->is_writable;
return entry;
}
gboolean
gconf_entry_equal (const GConfEntry *a,
const GConfEntry *b)
{
GConfRealEntry *real_a;
GConfRealEntry *real_b;
g_return_val_if_fail (a != NULL, FALSE);
g_return_val_if_fail (b != NULL, FALSE);
real_a = REAL_ENTRY (a);
real_b = REAL_ENTRY (b);
/* do the cheap checks first, why not */
if (real_a->value && !real_b->value)
return FALSE;
else if (!real_a->value && real_b->value)
return FALSE;
else if (real_a->is_default != real_b->is_default)
return FALSE;
else if (real_a->is_writable != real_b->is_writable)
return FALSE;
else if (strcmp (real_a->key, real_b->key) != 0)
return FALSE;
else if (real_a->schema_name && !real_b->schema_name)
return FALSE;
else if (!real_a->schema_name && real_b->schema_name)
return FALSE;
else if (real_a->schema_name && real_b->schema_name &&
strcmp (real_a->schema_name, real_b->schema_name) != 0)
return FALSE;
else if (real_a->value && real_b->value &&
gconf_value_compare (real_a->value, real_b->value) != 0)
return FALSE;
else
return TRUE;
}
GConfValue*
gconf_entry_steal_value (GConfEntry* entry)
{
GConfValue* val = REAL_ENTRY (entry)->value;
REAL_ENTRY (entry)->value = NULL;
return val;
}
const char*
gconf_entry_get_key (const GConfEntry *entry)
{
g_return_val_if_fail (entry != NULL, NULL);
return REAL_ENTRY (entry)->key;
}
GConfValue*
gconf_entry_get_value (const GConfEntry *entry)
{
g_return_val_if_fail (entry != NULL, NULL);
return REAL_ENTRY (entry)->value;
}
const char*
gconf_entry_get_schema_name (const GConfEntry *entry)
{
g_return_val_if_fail (entry != NULL, NULL);
return REAL_ENTRY (entry)->schema_name;
}
gboolean
gconf_entry_get_is_default (const GConfEntry *entry)
{
g_return_val_if_fail (entry != NULL, FALSE);
return REAL_ENTRY (entry)->is_default;
}
gboolean
gconf_entry_get_is_writable (const GConfEntry *entry)
{
g_return_val_if_fail (entry != NULL, FALSE);
return REAL_ENTRY (entry)->is_writable;
}
void
gconf_entry_set_value (GConfEntry *entry,
const GConfValue *val)
{
gconf_entry_set_value_nocopy (entry,
val ? gconf_value_copy (val) : NULL);
}
void
gconf_entry_set_value_nocopy(GConfEntry* entry,
GConfValue* val)
{
if (REAL_ENTRY (entry)->value)
gconf_value_free (REAL_ENTRY (entry)->value);
REAL_ENTRY (entry)->value = val;
}
void
gconf_entry_set_schema_name(GConfEntry* entry,
const gchar* name)
{
if (REAL_ENTRY (entry)->schema_name)
g_free (REAL_ENTRY (entry)->schema_name);
REAL_ENTRY (entry)->schema_name = name ? g_strdup(name) : NULL;
}
void
gconf_entry_set_is_default (GConfEntry* entry,
gboolean is_default)
{
REAL_ENTRY (entry)->is_default = is_default;
}
void
gconf_entry_set_is_writable (GConfEntry *entry,
gboolean is_writable)
{
REAL_ENTRY (entry)->is_writable = is_writable;
}
gboolean
gconf_value_validate (const GConfValue *value,
GError **err)
{
GConfRealValue *real;
g_return_val_if_fail (value != NULL, FALSE);
real = REAL_VALUE (value);
switch (value->type)
{
case GCONF_VALUE_STRING:
if (real->d.string_data &&
!g_utf8_validate (real->d.string_data, -1, NULL))
{
g_set_error (err, GCONF_ERROR,
GCONF_ERROR_FAILED,
_("Text contains invalid UTF-8"));
return FALSE;
}
break;
case GCONF_VALUE_SCHEMA:
if (real->d.schema_data)
return gconf_schema_validate (real->d.schema_data,
err);
break;
default:
break;
}
return TRUE;
}
syntax highlighted by Code2HTML, v. 0.9.1