1 /* GConf
2  * Copyright (C) 1999, 2000, 2002 Red Hat Inc.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19 
20 #include <config.h>
21 #include "gconf-value.h"
22 #include "gconf-error.h"
23 #include "gconf-schema.h"
24 #include "gconf-internals.h"
25 #include <errno.h>
26 #include <string.h>
27 #include <stdlib.h>
28 
29 typedef struct {
30   GConfValueType type;
31   union {
32     gchar* string_data;
33     gint int_data;
34     gboolean bool_data;
35     gdouble float_data;
36     GConfSchema* schema_data;
37     struct {
38       GConfValueType type;
39       GSList* list;
40     } list_data;
41     struct {
42       GConfValue* car;
43       GConfValue* cdr;
44     } pair_data;
45   } d;
46 } GConfRealValue;
47 
48 #define REAL_VALUE(x) ((GConfRealValue*)(x))
49 
50 static void
set_string(gchar ** dest,const gchar * src)51 set_string(gchar** dest, const gchar* src)
52 {
53   g_free(*dest);
54   *dest = g_strdup(src);
55 }
56 
57 /*
58  * Values
59  */
60 
61 GConfValue*
gconf_value_new(GConfValueType type)62 gconf_value_new(GConfValueType type)
63 {
64   GConfValue* value;
65   static gboolean initted = FALSE;
66 
67   g_return_val_if_fail(GCONF_VALUE_TYPE_VALID(type), NULL);
68 
69   if (!initted)
70     {
71       _gconf_init_i18n ();
72       initted = TRUE;
73     }
74 
75   value = (GConfValue*) g_slice_new0 (GConfRealValue);
76 
77   value->type = type;
78 
79   /* the g_new0() is important: sets list type to invalid, NULLs all
80    * pointers
81    */
82 
83   return value;
84 }
85 
86 GConfValue*
gconf_value_new_from_string(GConfValueType type,const gchar * value_str,GError ** err)87 gconf_value_new_from_string(GConfValueType type, const gchar* value_str,
88                              GError** err)
89 {
90   GConfValue* value;
91 
92   g_return_val_if_fail (type != GCONF_VALUE_LIST, NULL);
93   g_return_val_if_fail (type != GCONF_VALUE_PAIR, NULL);
94 
95   value = gconf_value_new(type);
96 
97   switch (type)
98     {
99     case GCONF_VALUE_INT:
100       {
101         char* endptr = NULL;
102         glong result;
103 
104         errno = 0;
105         result = strtol(value_str, &endptr, 10);
106 
107         if (endptr == value_str)
108           {
109             if (err)
110               *err = gconf_error_new(GCONF_ERROR_PARSE_ERROR,
111                                       _("Didn't understand `%s' (expected integer)"),
112                                       value_str);
113 
114             gconf_value_free(value);
115             value = NULL;
116           }
117         else if (errno == ERANGE)
118           {
119             if (err)
120               *err = gconf_error_new(GCONF_ERROR_PARSE_ERROR,
121                                       _("Integer `%s' is too large or small"),
122                                       value_str);
123             gconf_value_free(value);
124             value = NULL;
125           }
126         else
127           gconf_value_set_int(value, result);
128       }
129       break;
130     case GCONF_VALUE_FLOAT:
131       {
132         double num;
133 
134         if (gconf_string_to_double(value_str, &num))
135           {
136             gconf_value_set_float(value, num);
137           }
138         else
139           {
140             if (err)
141               *err = gconf_error_new(GCONF_ERROR_PARSE_ERROR,
142                                       _("Didn't understand `%s' (expected real number)"),
143                                      value_str);
144 
145             gconf_value_free(value);
146             value = NULL;
147           }
148       }
149       break;
150     case GCONF_VALUE_STRING:
151       if (!g_utf8_validate (value_str, -1, NULL))
152         {
153           g_set_error (err, GCONF_ERROR,
154                        GCONF_ERROR_PARSE_ERROR,
155                        _("Text contains invalid UTF-8"));
156           gconf_value_free(value);
157           value = NULL;
158         }
159       else
160         {
161           gconf_value_set_string(value, value_str);
162         }
163       break;
164     case GCONF_VALUE_BOOL:
165       switch (*value_str)
166         {
167         case 't':
168         case 'T':
169         case '1':
170         case 'y':
171         case 'Y':
172           gconf_value_set_bool(value, TRUE);
173           break;
174 
175         case 'f':
176         case 'F':
177         case '0':
178         case 'n':
179         case 'N':
180           gconf_value_set_bool(value, FALSE);
181           break;
182 
183         default:
184           if (err)
185             *err = gconf_error_new(GCONF_ERROR_PARSE_ERROR,
186                                    _("Didn't understand `%s' (expected true or false)"),
187                                    value_str);
188 
189           gconf_value_free(value);
190           value = NULL;
191           break;
192         }
193       break;
194     case GCONF_VALUE_LIST:
195     case GCONF_VALUE_PAIR:
196     default:
197       g_assert_not_reached();
198       break;
199     }
200 
201   return value;
202 }
203 
204 static char *
escape_string(const char * str,const char * escaped_chars)205 escape_string(const char *str, const char *escaped_chars)
206 {
207   gint i, j, len;
208   gchar* ret;
209 
210   len = 0;
211   for (i = 0; str[i] != '\0'; i++)
212     {
213       if (strchr(escaped_chars, str[i]) != NULL ||
214 	  str[i] == '\\')
215 	len++;
216       len++;
217     }
218 
219   ret = g_malloc(len + 1);
220 
221   j = 0;
222   for (i = 0; str[i] != '\0'; i++)
223     {
224       if (strchr(escaped_chars, str[i]) != NULL ||
225 	  str[i] == '\\')
226 	{
227 	  ret[j++] = '\\';
228 	}
229       ret[j++] = str[i];
230     }
231   ret[j++] = '\0';
232 
233   return ret;
234 }
235 
236 GConfValue*
gconf_value_new_list_from_string(GConfValueType list_type,const gchar * str,GError ** err)237 gconf_value_new_list_from_string(GConfValueType list_type,
238                                   const gchar* str,
239 				  GError** err)
240 {
241   int i, len;
242   gboolean escaped, pending_chars;
243   GString *string;
244   GConfValue* value;
245   GSList *list;
246 
247   g_return_val_if_fail(list_type != GCONF_VALUE_LIST, NULL);
248   g_return_val_if_fail(list_type != GCONF_VALUE_PAIR, NULL);
249 
250   if (!g_utf8_validate (str, -1, NULL))
251     {
252       g_set_error (err, GCONF_ERROR,
253                    GCONF_ERROR_PARSE_ERROR,
254                    _("Text contains invalid UTF-8"));
255       return NULL;
256     }
257 
258   if (str[0] != '[')
259     {
260       if (err)
261 	*err = gconf_error_new(GCONF_ERROR_PARSE_ERROR,
262 			       _("Didn't understand `%s' (list must start with a '[')"),
263 			       str);
264       return NULL;
265     }
266 
267   len = strlen(str);
268 
269   /* Note: by now len is sure to be 1 or larger, so len-1 will never be
270    * negative */
271   if (str[len-1] != ']')
272     {
273       if (err)
274 	*err = gconf_error_new(GCONF_ERROR_PARSE_ERROR,
275 			       _("Didn't understand `%s' (list must end with a ']')"),
276 			       str);
277       return NULL;
278     }
279 
280   if (strstr(str, "[]"))
281     {
282       value = gconf_value_new(GCONF_VALUE_LIST);
283       gconf_value_set_list_type(value, list_type);
284 
285       return value;
286     }
287 
288   escaped = FALSE;
289   pending_chars = FALSE;
290   list = NULL;
291   string = g_string_new(NULL);
292 
293   for (i = 1; str[i] != '\0'; i++)
294     {
295       if ( ! escaped &&
296 	  (str[i] == ',' ||
297 	   str[i] == ']'))
298 	{
299 	  GConfValue* val;
300 	  val = gconf_value_new_from_string(list_type, string->str, err);
301 
302 	  if (err && *err != NULL)
303 	    {
304 	      /* Free values so far */
305 	      g_slist_foreach(list, (GFunc)gconf_value_free, NULL);
306 	      g_slist_free(list);
307 
308 	      g_string_free(string, TRUE);
309 
310 	      return NULL;
311 	    }
312 
313 	  g_string_assign(string, "");
314 	  list = g_slist_prepend(list, val);
315 	  if (str[i] == ']' &&
316 	      i != len-1)
317 	    {
318 	      /* Free values so far */
319 	      g_slist_foreach(list, (GFunc)gconf_value_free, NULL);
320 	      g_slist_free(list);
321 
322 	      g_string_free(string, TRUE);
323 
324 	      if (err)
325 		*err = gconf_error_new(GCONF_ERROR_PARSE_ERROR,
326 				       _("Didn't understand `%s' (extra unescaped ']' found inside list)"),
327 				       str);
328 	      return NULL;
329 	    }
330 	  pending_chars = FALSE;
331 	}
332       else if ( ! escaped && str[i] == '\\')
333 	{
334 	  escaped = TRUE;
335 	  pending_chars = TRUE;
336 	}
337       else
338 	{
339 	  g_string_append_c(string, str[i]);
340 	  escaped = FALSE;
341 	  pending_chars = TRUE;
342 	}
343     }
344 
345   g_string_free(string, TRUE);
346 
347   if (pending_chars)
348     {
349       /* Free values so far */
350       g_slist_foreach(list, (GFunc)gconf_value_free, NULL);
351       g_slist_free(list);
352 
353       g_string_free(string, TRUE);
354 
355       if (err)
356 	*err = gconf_error_new(GCONF_ERROR_PARSE_ERROR,
357 			       _("Didn't understand `%s' (extra trailing characters)"),
358 			       str);
359       return NULL;
360     }
361 
362   /* inverse list as we were prepending to it */
363   list = g_slist_reverse(list);
364 
365   value = gconf_value_new(GCONF_VALUE_LIST);
366   gconf_value_set_list_type(value, list_type);
367 
368   gconf_value_set_list_nocopy(value, list);
369 
370   return value;
371 }
372 
373 GConfValue*
gconf_value_new_pair_from_string(GConfValueType car_type,GConfValueType cdr_type,const gchar * str,GError ** err)374 gconf_value_new_pair_from_string(GConfValueType car_type,
375                                   GConfValueType cdr_type,
376                                   const gchar* str,
377 				  GError** err)
378 {
379   int i, len;
380   int elem;
381   gboolean escaped, pending_chars;
382   GString *string;
383   GConfValue* value;
384   GConfValue* car;
385   GConfValue* cdr;
386 
387   g_return_val_if_fail(car_type != GCONF_VALUE_LIST, NULL);
388   g_return_val_if_fail(car_type != GCONF_VALUE_PAIR, NULL);
389   g_return_val_if_fail(cdr_type != GCONF_VALUE_LIST, NULL);
390   g_return_val_if_fail(cdr_type != GCONF_VALUE_PAIR, NULL);
391 
392   if (!g_utf8_validate (str, -1, NULL))
393     {
394       g_set_error (err, GCONF_ERROR,
395                    GCONF_ERROR_PARSE_ERROR,
396                    _("Text contains invalid UTF-8"));
397       return NULL;
398     }
399 
400   if (str[0] != '(')
401     {
402       if (err)
403 	*err = gconf_error_new(GCONF_ERROR_PARSE_ERROR,
404 			       _("Didn't understand `%s' (pair must start with a '(')"),
405 			       str);
406       return NULL;
407     }
408 
409   len = strlen(str);
410 
411   /* Note: by now len is sure to be 1 or larger, so len-1 will never be
412    * negative */
413   if (str[len-1] != ')')
414     {
415       if (err)
416 	*err = gconf_error_new(GCONF_ERROR_PARSE_ERROR,
417 			       _("Didn't understand `%s' (pair must end with a ')')"),
418 			       str);
419       return NULL;
420     }
421 
422   escaped = FALSE;
423   pending_chars = FALSE;
424   car = cdr = NULL;
425   string = g_string_new(NULL);
426   elem = 0;
427 
428   for (i = 1; str[i] != '\0'; i++)
429     {
430       if ( ! escaped &&
431 	  (str[i] == ',' ||
432 	   str[i] == ')'))
433 	{
434 	  if ((str[i] == ')' && elem != 1) ||
435 	      (elem > 1))
436 	    {
437 	      /* Free values so far */
438 	      if (car)
439 	        gconf_value_free(car);
440 	      if (cdr)
441 	        gconf_value_free(cdr);
442 
443 	      g_string_free(string, TRUE);
444 
445 	      if (err)
446 		*err = gconf_error_new(GCONF_ERROR_PARSE_ERROR,
447 				       _("Didn't understand `%s' (wrong number of elements)"),
448 				       str);
449 	      return NULL;
450 	    }
451 
452 	  if (elem == 0)
453 	    car = gconf_value_new_from_string(car_type, string->str, err);
454 	  else if (elem == 1)
455 	    cdr = gconf_value_new_from_string(cdr_type, string->str, err);
456 
457 	  elem ++;
458 
459 	  if (err && *err != NULL)
460 	    {
461 	      /* Free values so far */
462 	      if (car)
463 	        gconf_value_free(car);
464 	      if (cdr)
465 	        gconf_value_free(cdr);
466 
467 	      g_string_free(string, TRUE);
468 
469 	      return NULL;
470 	    }
471 
472 	  g_string_assign(string, "");
473 
474 	  if (str[i] == ')' &&
475 	      i != len-1)
476 	    {
477 	      /* Free values so far */
478 	      if (car)
479 	        gconf_value_free(car);
480 	      if (cdr)
481 	        gconf_value_free(cdr);
482 
483 	      g_string_free(string, TRUE);
484 
485 	      if (err)
486 		*err = gconf_error_new(GCONF_ERROR_PARSE_ERROR,
487 				       _("Didn't understand `%s' (extra unescaped ')' found inside pair)"),
488 				       str);
489 	      return NULL;
490 	    }
491 	  pending_chars = FALSE;
492 	}
493       else if ( ! escaped && str[i] == '\\')
494 	{
495 	  escaped = TRUE;
496 	  pending_chars = TRUE;
497 	}
498       else
499 	{
500 	  g_string_append_c(string, str[i]);
501 	  escaped = FALSE;
502 	  pending_chars = TRUE;
503 	}
504     }
505 
506   g_string_free(string, TRUE);
507 
508   if (pending_chars)
509     {
510       /* Free values so far */
511       if (car)
512 	gconf_value_free(car);
513       if (cdr)
514 	gconf_value_free(cdr);
515 
516       if (err)
517 	*err = gconf_error_new(GCONF_ERROR_PARSE_ERROR,
518 			       _("Didn't understand `%s' (extra trailing characters)"),
519 			       str);
520       return NULL;
521     }
522 
523   if (elem != 2)
524     {
525       /* Free values so far */
526       if (car)
527 	gconf_value_free(car);
528       if (cdr)
529 	gconf_value_free(cdr);
530 
531       if (err)
532 	*err = gconf_error_new(GCONF_ERROR_PARSE_ERROR,
533 			       _("Didn't understand `%s' (wrong number of elements)"),
534 			       str);
535       return NULL;
536     }
537 
538   value = gconf_value_new(GCONF_VALUE_PAIR);
539   gconf_value_set_car_nocopy(value, car);
540   gconf_value_set_cdr_nocopy(value, cdr);
541 
542   return value;
543 }
544 
545 gchar*
gconf_value_to_string(const GConfValue * value)546 gconf_value_to_string(const GConfValue* value)
547 {
548   /* These strings shouldn't be translated; they're primarily
549      intended for machines to read, not humans, though I do
550      use them in some debug spew
551   */
552   gchar* retval = NULL;
553 
554   switch (value->type)
555     {
556     case GCONF_VALUE_INT:
557       retval = g_strdup_printf("%d", gconf_value_get_int(value));
558       break;
559     case GCONF_VALUE_FLOAT:
560       retval = gconf_double_to_string(gconf_value_get_float(value));
561       break;
562     case GCONF_VALUE_STRING:
563       retval = g_strdup(gconf_value_get_string(value));
564       break;
565     case GCONF_VALUE_BOOL:
566       retval = gconf_value_get_bool(value) ? g_strdup("true") : g_strdup("false");
567       break;
568     case GCONF_VALUE_LIST:
569       {
570         GSList* list;
571 
572         list = gconf_value_get_list(value);
573 
574         if (list == NULL)
575           retval = g_strdup("[]");
576         else
577           {
578             gchar* buf = NULL;
579             guint bufsize = 64;
580             guint cur = 0;
581 
582             g_assert(list != NULL);
583 
584             buf = g_malloc(bufsize+3); /* my +3 superstition */
585 
586             buf[0] = '[';
587             ++cur;
588 
589             g_assert(cur < bufsize);
590 
591             while (list != NULL)
592               {
593                 gchar* tmp;
594                 gchar* elem;
595                 guint len;
596 
597                 tmp = gconf_value_to_string((GConfValue*)list->data);
598 
599                 g_assert(tmp != NULL);
600 
601 		elem = escape_string(tmp, ",]");
602 
603 		g_free(tmp);
604 
605                 len = strlen(elem);
606 
607                 if ((cur + len + 2) >= bufsize) /* +2 for '\0' and comma */
608                   {
609                     bufsize = MAX(bufsize*2, bufsize+len+4);
610                     buf = g_realloc(buf, bufsize+3);
611                   }
612 
613                 g_assert(cur < bufsize);
614 
615                 strcpy(&buf[cur], elem);
616                 cur += len;
617 
618                 g_assert(cur < bufsize);
619 
620                 g_free(elem);
621 
622                 buf[cur] = ',';
623                 ++cur;
624 
625                 g_assert(cur < bufsize);
626 
627                 list = g_slist_next(list);
628               }
629 
630             g_assert(cur < bufsize);
631 
632             buf[cur-1] = ']'; /* overwrites last comma */
633             buf[cur] = '\0';
634 
635             retval = buf;
636           }
637       }
638       break;
639     case GCONF_VALUE_PAIR:
640       {
641         gchar* tmp;
642         gchar* car;
643         gchar* cdr;
644 
645         if (gconf_value_get_car (value))
646           tmp = gconf_value_to_string(gconf_value_get_car(value));
647         else
648           tmp = g_strdup ("nil");
649 	car = escape_string(tmp, ",)");
650 	g_free(tmp);
651 
652         if (gconf_value_get_cdr (value))
653           tmp = gconf_value_to_string(gconf_value_get_cdr(value));
654         else
655           tmp = g_strdup ("nil");
656 	cdr = escape_string(tmp, ",)");
657 	g_free(tmp);
658         retval = g_strdup_printf("(%s,%s)", car, cdr);
659         g_free(car);
660         g_free(cdr);
661       }
662       break;
663       /* These remaining shouldn't really be used outside of debug spew... */
664     case GCONF_VALUE_INVALID:
665       retval = g_strdup("Invalid");
666       break;
667     case GCONF_VALUE_SCHEMA:
668       {
669         const gchar* locale;
670         const gchar* type;
671         const gchar* list_type;
672         const gchar* car_type;
673         const gchar* cdr_type;
674 
675         locale = gconf_schema_get_locale(gconf_value_get_schema(value));
676         type = gconf_value_type_to_string(gconf_schema_get_type(gconf_value_get_schema(value)));
677         list_type = gconf_value_type_to_string(gconf_schema_get_list_type(gconf_value_get_schema(value)));
678         car_type = gconf_value_type_to_string(gconf_schema_get_car_type(gconf_value_get_schema(value)));
679         cdr_type = gconf_value_type_to_string(gconf_schema_get_cdr_type(gconf_value_get_schema(value)));
680 
681         retval = g_strdup_printf("Schema (type: `%s' list_type: '%s' "
682 				 "car_type: '%s' cdr_type: '%s' locale: `%s')",
683                                  type, list_type, car_type, cdr_type,
684 				 locale ? locale : "(null)");
685       }
686       break;
687     default:
688       g_assert_not_reached();
689       break;
690     }
691 
692   return retval;
693 }
694 
695 static GSList*
copy_value_list(GSList * list)696 copy_value_list(GSList* list)
697 {
698   GSList* copy = NULL;
699   GSList* tmp = list;
700 
701   while (tmp != NULL)
702     {
703       copy = g_slist_prepend(copy, gconf_value_copy(tmp->data));
704 
705       tmp = g_slist_next(tmp);
706     }
707 
708   copy = g_slist_reverse(copy);
709 
710   return copy;
711 }
712 
713 GType
gconf_value_get_type()714 gconf_value_get_type ()
715 {
716   static GType type = 0;
717 
718   if (type == 0)
719     type = g_boxed_type_register_static (g_intern_static_string ("GConfValue"),
720                                          (GBoxedCopyFunc) gconf_value_copy,
721                                          (GBoxedFreeFunc) gconf_value_free);
722   return type;
723 }
724 
725 GConfValue*
gconf_value_copy(const GConfValue * src)726 gconf_value_copy (const GConfValue* src)
727 {
728   GConfRealValue *dest;
729   GConfRealValue *real;
730 
731   g_return_val_if_fail(src != NULL, NULL);
732 
733   real = REAL_VALUE (src);
734   dest = REAL_VALUE (gconf_value_new (src->type));
735 
736   switch (real->type)
737     {
738     case GCONF_VALUE_INT:
739     case GCONF_VALUE_FLOAT:
740     case GCONF_VALUE_BOOL:
741     case GCONF_VALUE_INVALID:
742       dest->d = real->d;
743       break;
744     case GCONF_VALUE_STRING:
745       set_string(&dest->d.string_data, real->d.string_data);
746       break;
747     case GCONF_VALUE_SCHEMA:
748       if (real->d.schema_data)
749         dest->d.schema_data = gconf_schema_copy(real->d.schema_data);
750       else
751         dest->d.schema_data = NULL;
752       break;
753 
754     case GCONF_VALUE_LIST:
755       {
756         GSList* copy;
757 
758         copy = copy_value_list(real->d.list_data.list);
759 
760         dest->d.list_data.list = copy;
761         dest->d.list_data.type = real->d.list_data.type;
762       }
763       break;
764 
765     case GCONF_VALUE_PAIR:
766 
767       if (real->d.pair_data.car)
768         dest->d.pair_data.car = gconf_value_copy(real->d.pair_data.car);
769       else
770         dest->d.pair_data.car = NULL;
771 
772       if (real->d.pair_data.cdr)
773         dest->d.pair_data.cdr = gconf_value_copy(real->d.pair_data.cdr);
774       else
775         dest->d.pair_data.cdr = NULL;
776 
777       break;
778 
779     default:
780       g_assert_not_reached();
781     }
782 
783   return (GConfValue*) dest;
784 }
785 
786 static void
gconf_value_free_list(GConfValue * value)787 gconf_value_free_list(GConfValue* value)
788 {
789   GSList* tmp;
790   GConfRealValue *real;
791 
792   g_return_if_fail(value != NULL);
793   g_return_if_fail(value->type == GCONF_VALUE_LIST);
794 
795   real = REAL_VALUE (value);
796 
797   tmp = real->d.list_data.list;
798 
799   while (tmp != NULL)
800     {
801       gconf_value_free(tmp->data);
802 
803       tmp = g_slist_next(tmp);
804     }
805   g_slist_free(real->d.list_data.list);
806 
807   real->d.list_data.list = NULL;
808 }
809 
810 void
gconf_value_free(GConfValue * value)811 gconf_value_free(GConfValue* value)
812 {
813   GConfRealValue *real;
814 
815   g_return_if_fail(value != NULL);
816 
817   real = REAL_VALUE (value);
818 
819   switch (real->type)
820     {
821     case GCONF_VALUE_STRING:
822       g_free(real->d.string_data);
823       break;
824     case GCONF_VALUE_SCHEMA:
825       if (real->d.schema_data != NULL)
826         gconf_schema_free(real->d.schema_data);
827       break;
828     case GCONF_VALUE_LIST:
829       gconf_value_free_list(value);
830       break;
831     case GCONF_VALUE_PAIR:
832       if (real->d.pair_data.car != NULL)
833         gconf_value_free(real->d.pair_data.car);
834 
835       if (real->d.pair_data.cdr != NULL)
836         gconf_value_free(real->d.pair_data.cdr);
837       break;
838     default:
839       break;
840     }
841 
842   g_slice_free(GConfRealValue, real);
843 }
844 
845 const char*
gconf_value_get_string(const GConfValue * value)846 gconf_value_get_string (const GConfValue *value)
847 {
848   g_return_val_if_fail (value != NULL, NULL);
849   g_return_val_if_fail (value->type == GCONF_VALUE_STRING, NULL);
850 
851   return REAL_VALUE (value)->d.string_data;
852 }
853 
854 char*
gconf_value_steal_string(GConfValue * value)855 gconf_value_steal_string (GConfValue *value)
856 {
857   char *string;
858   GConfRealValue *real;
859 
860   g_return_val_if_fail (value != NULL, NULL);
861   g_return_val_if_fail (value->type == GCONF_VALUE_STRING, NULL);
862 
863   real = REAL_VALUE (value);
864 
865   string = real->d.string_data;
866   real->d.string_data = NULL;
867 
868   return string;
869 }
870 
871 int
gconf_value_get_int(const GConfValue * value)872 gconf_value_get_int (const GConfValue *value)
873 {
874   g_return_val_if_fail (value != NULL, 0);
875   g_return_val_if_fail (value->type == GCONF_VALUE_INT, 0);
876 
877   return REAL_VALUE (value)->d.int_data;
878 }
879 
880 double
gconf_value_get_float(const GConfValue * value)881 gconf_value_get_float (const GConfValue *value)
882 {
883   g_return_val_if_fail (value != NULL, 0.0);
884   g_return_val_if_fail (value->type == GCONF_VALUE_FLOAT, 0.0);
885 
886   return REAL_VALUE (value)->d.float_data;
887 }
888 
889 GConfValueType
gconf_value_get_list_type(const GConfValue * value)890 gconf_value_get_list_type (const GConfValue *value)
891 {
892   g_return_val_if_fail (value != NULL, GCONF_VALUE_INVALID);
893   g_return_val_if_fail (value->type == GCONF_VALUE_LIST, GCONF_VALUE_INVALID);
894 
895   return REAL_VALUE (value)->d.list_data.type;
896 }
897 
898 /**
899  * gconf_value_get_list:
900  * @value: a #GConfValue.
901  *
902  * Returns a #GSList containing #GConfValue objects. Each #GConfValue in
903  * the returned list will have the type returned by
904  * gconf_value_get_list_type(). Remember that the empty #GSList is equal to
905  * <symbol>NULL</symbol>.  The list is not a copy; it is "owned" by the
906  * #GConfValue and will be destroyed when the #GConfValue is destroyed.
907  *
908  * Return value: (element-type GConfValue) (transfer none): a #GList.
909  */
910 GSList*
gconf_value_get_list(const GConfValue * value)911 gconf_value_get_list (const GConfValue *value)
912 {
913   g_return_val_if_fail (value != NULL, NULL);
914   g_return_val_if_fail (value->type == GCONF_VALUE_LIST, NULL);
915 
916   return REAL_VALUE (value)->d.list_data.list;
917 }
918 
919 GSList*
gconf_value_steal_list(GConfValue * value)920 gconf_value_steal_list (GConfValue *value)
921 {
922   GSList *list;
923   GConfRealValue *real;
924 
925   g_return_val_if_fail (value != NULL, NULL);
926   g_return_val_if_fail (value->type == GCONF_VALUE_LIST, NULL);
927 
928   real = REAL_VALUE (value);
929 
930   list = real->d.list_data.list;
931   real->d.list_data.list = NULL;
932   return list;
933 }
934 
935 GConfValue*
gconf_value_get_car(const GConfValue * value)936 gconf_value_get_car (const GConfValue *value)
937 {
938   g_return_val_if_fail (value != NULL, NULL);
939   g_return_val_if_fail (value->type == GCONF_VALUE_PAIR, NULL);
940 
941   return REAL_VALUE (value)->d.pair_data.car;
942 }
943 
944 GConfValue*
gconf_value_get_cdr(const GConfValue * value)945 gconf_value_get_cdr (const GConfValue *value)
946 {
947   g_return_val_if_fail (value != NULL, NULL);
948   g_return_val_if_fail (value->type == GCONF_VALUE_PAIR, NULL);
949 
950   return REAL_VALUE (value)->d.pair_data.cdr;
951 }
952 
953 
954 gboolean
gconf_value_get_bool(const GConfValue * value)955 gconf_value_get_bool (const GConfValue *value)
956 {
957   g_return_val_if_fail (value != NULL, FALSE);
958   g_return_val_if_fail (value->type == GCONF_VALUE_BOOL, FALSE);
959 
960   return REAL_VALUE (value)->d.bool_data;
961 }
962 
963 GConfSchema*
gconf_value_get_schema(const GConfValue * value)964 gconf_value_get_schema (const GConfValue *value)
965 {
966   g_return_val_if_fail (value != NULL, NULL);
967   g_return_val_if_fail (value->type == GCONF_VALUE_SCHEMA, NULL);
968 
969   return REAL_VALUE (value)->d.schema_data;
970 }
971 
972 GConfSchema*
gconf_value_steal_schema(GConfValue * value)973 gconf_value_steal_schema (GConfValue *value)
974 {
975   GConfSchema *schema;
976   GConfRealValue *real;
977 
978   g_return_val_if_fail (value != NULL, NULL);
979   g_return_val_if_fail (value->type == GCONF_VALUE_SCHEMA, NULL);
980 
981   real = REAL_VALUE (value);
982 
983   schema = real->d.schema_data;
984   real->d.schema_data = NULL;
985 
986   return schema;
987 }
988 
989 void
gconf_value_set_int(GConfValue * value,gint the_int)990 gconf_value_set_int(GConfValue* value, gint the_int)
991 {
992   g_return_if_fail(value != NULL);
993   g_return_if_fail(value->type == GCONF_VALUE_INT);
994 
995   REAL_VALUE (value)->d.int_data = the_int;
996 }
997 
998 void
gconf_value_set_string(GConfValue * value,const gchar * the_str)999 gconf_value_set_string(GConfValue* value, const gchar* the_str)
1000 {
1001   gconf_value_set_string_nocopy (value,
1002                                  g_strdup (the_str));
1003 }
1004 
1005 void
gconf_value_set_string_nocopy(GConfValue * value,char * str)1006 gconf_value_set_string_nocopy (GConfValue *value,
1007                                char       *str)
1008 {
1009   GConfRealValue *real;
1010 
1011   g_return_if_fail(value != NULL);
1012   g_return_if_fail(value->type == GCONF_VALUE_STRING);
1013 
1014   real = REAL_VALUE (value);
1015 
1016   g_free (real->d.string_data);
1017   real->d.string_data = str;
1018 }
1019 
1020 void
gconf_value_set_float(GConfValue * value,gdouble the_float)1021 gconf_value_set_float(GConfValue* value, gdouble the_float)
1022 {
1023   g_return_if_fail(value != NULL);
1024   g_return_if_fail(value->type == GCONF_VALUE_FLOAT);
1025 
1026   REAL_VALUE (value)->d.float_data = the_float;
1027 }
1028 
1029 void
gconf_value_set_bool(GConfValue * value,gboolean the_bool)1030 gconf_value_set_bool(GConfValue* value, gboolean the_bool)
1031 {
1032   g_return_if_fail(value != NULL);
1033   g_return_if_fail(value->type == GCONF_VALUE_BOOL);
1034 
1035   REAL_VALUE (value)->d.bool_data = the_bool;
1036 }
1037 
1038 void
gconf_value_set_schema(GConfValue * value,const GConfSchema * sc)1039 gconf_value_set_schema(GConfValue* value, const GConfSchema* sc)
1040 {
1041   GConfRealValue *real;
1042 
1043   g_return_if_fail(value != NULL);
1044   g_return_if_fail(value->type == GCONF_VALUE_SCHEMA);
1045 
1046   real = REAL_VALUE (value);
1047 
1048   if (real->d.schema_data != NULL)
1049     gconf_schema_free (real->d.schema_data);
1050 
1051   real->d.schema_data = gconf_schema_copy (sc);
1052 }
1053 
1054 void
gconf_value_set_schema_nocopy(GConfValue * value,GConfSchema * sc)1055 gconf_value_set_schema_nocopy(GConfValue* value, GConfSchema* sc)
1056 {
1057   GConfRealValue *real;
1058 
1059   g_return_if_fail(value != NULL);
1060   g_return_if_fail(value->type == GCONF_VALUE_SCHEMA);
1061   g_return_if_fail(sc != NULL);
1062 
1063   real = REAL_VALUE (value);
1064 
1065   if (real->d.schema_data != NULL)
1066     gconf_schema_free (real->d.schema_data);
1067 
1068   real->d.schema_data = sc;
1069 }
1070 
1071 void
gconf_value_set_car(GConfValue * value,const GConfValue * car)1072 gconf_value_set_car(GConfValue* value, const GConfValue* car)
1073 {
1074   gconf_value_set_car_nocopy(value, gconf_value_copy(car));
1075 }
1076 
1077 void
gconf_value_set_car_nocopy(GConfValue * value,GConfValue * car)1078 gconf_value_set_car_nocopy(GConfValue* value, GConfValue* car)
1079 {
1080   GConfRealValue *real;
1081 
1082   g_return_if_fail(value != NULL);
1083   g_return_if_fail(value->type == GCONF_VALUE_PAIR);
1084 
1085   real = REAL_VALUE (value);
1086 
1087   if (real->d.pair_data.car != NULL)
1088     gconf_value_free (real->d.pair_data.car);
1089 
1090   real->d.pair_data.car = car;
1091 }
1092 
1093 void
gconf_value_set_cdr(GConfValue * value,const GConfValue * cdr)1094 gconf_value_set_cdr(GConfValue* value, const GConfValue* cdr)
1095 {
1096   gconf_value_set_cdr_nocopy(value, gconf_value_copy(cdr));
1097 }
1098 
1099 void
gconf_value_set_cdr_nocopy(GConfValue * value,GConfValue * cdr)1100 gconf_value_set_cdr_nocopy(GConfValue* value, GConfValue* cdr)
1101 {
1102   GConfRealValue *real;
1103 
1104   g_return_if_fail(value != NULL);
1105   g_return_if_fail(value->type == GCONF_VALUE_PAIR);
1106 
1107   real = REAL_VALUE (value);
1108 
1109   if (real->d.pair_data.cdr != NULL)
1110     gconf_value_free (real->d.pair_data.cdr);
1111 
1112   real->d.pair_data.cdr = cdr;
1113 }
1114 
1115 void
gconf_value_set_list_type(GConfValue * value,GConfValueType type)1116 gconf_value_set_list_type (GConfValue    *value,
1117                            GConfValueType type)
1118 {
1119   GConfRealValue *real;
1120 
1121   g_return_if_fail(value != NULL);
1122   g_return_if_fail(value->type == GCONF_VALUE_LIST);
1123   g_return_if_fail(type != GCONF_VALUE_LIST);
1124   g_return_if_fail(type != GCONF_VALUE_PAIR);
1125 
1126   real = REAL_VALUE (value);
1127 
1128   /* If the list is non-NULL either we already have the right
1129    * type, or we shouldn't be changing it without deleting
1130    * the list first.
1131    */
1132   g_return_if_fail (real->d.list_data.list == NULL);
1133 
1134   real->d.list_data.type = type;
1135 }
1136 
1137 void
gconf_value_set_list_nocopy(GConfValue * value,GSList * list)1138 gconf_value_set_list_nocopy (GConfValue* value,
1139                              GSList* list)
1140 {
1141   GConfRealValue *real;
1142 
1143   g_return_if_fail (value != NULL);
1144   g_return_if_fail (value->type == GCONF_VALUE_LIST);
1145 
1146   real = REAL_VALUE (value);
1147 
1148   g_return_if_fail (real->d.list_data.type != GCONF_VALUE_INVALID);
1149 
1150   if (real->d.list_data.list)
1151     gconf_value_free_list (value);
1152 
1153   real->d.list_data.list = list;
1154 }
1155 
1156 void
gconf_value_set_list(GConfValue * value,GSList * list)1157 gconf_value_set_list       (GConfValue* value,
1158                             GSList* list)
1159 {
1160   GConfRealValue *real;
1161 
1162   g_return_if_fail (value != NULL);
1163   g_return_if_fail (value->type == GCONF_VALUE_LIST);
1164 
1165   real = REAL_VALUE (value);
1166 
1167   g_return_if_fail (real->d.list_data.type != GCONF_VALUE_INVALID);
1168   g_return_if_fail ((list == NULL) ||
1169                     ((list->data != NULL) &&
1170                      (((GConfValue*)list->data)->type == real->d.list_data.type)));
1171 
1172   if (real->d.list_data.list)
1173     gconf_value_free_list (value);
1174 
1175   real->d.list_data.list = copy_value_list (list);
1176 }
1177 
1178 
1179 static int
null_safe_strcmp(const char * lhs,const char * rhs)1180 null_safe_strcmp (const char *lhs,
1181                   const char *rhs)
1182 {
1183   if (lhs == NULL && rhs == NULL)
1184     return 0;
1185   else if (lhs == NULL)
1186     return -1;
1187   else if (rhs == NULL)
1188     return 1;
1189   else
1190     return strcmp (lhs, rhs);
1191 }
1192 
1193 int
gconf_value_compare(const GConfValue * value_a,const GConfValue * value_b)1194 gconf_value_compare (const GConfValue *value_a,
1195                      const GConfValue *value_b)
1196 {
1197   g_return_val_if_fail (value_a != NULL, 0);
1198   g_return_val_if_fail (value_b != NULL, 0);
1199 
1200   /* Impose arbitrary type ordering, just to keep the
1201    * sort invariants stable.
1202    */
1203   if (value_a->type < value_b->type)
1204     return -1;
1205   else if (value_a->type > value_b->type)
1206     return 1;
1207 
1208   switch (value_a->type)
1209     {
1210     case GCONF_VALUE_INT:
1211       if (gconf_value_get_int (value_a) < gconf_value_get_int (value_b))
1212         return -1;
1213       else if (gconf_value_get_int (value_a) > gconf_value_get_int (value_b))
1214         return 1;
1215       else
1216         return 0;
1217     case GCONF_VALUE_FLOAT:
1218       if (gconf_value_get_float (value_a) < gconf_value_get_float (value_b))
1219         return -1;
1220       else if (gconf_value_get_float (value_a) > gconf_value_get_float (value_b))
1221         return 1;
1222       else
1223         return 0;
1224     case GCONF_VALUE_STRING:
1225       return strcmp (gconf_value_get_string (value_a),
1226                      gconf_value_get_string (value_b));
1227     case GCONF_VALUE_BOOL:
1228       if (gconf_value_get_bool (value_a) == gconf_value_get_bool (value_b))
1229         return 0;
1230       /* make TRUE > FALSE to maintain sort invariants */
1231       else if (gconf_value_get_bool (value_a))
1232         return 1;
1233       else
1234         return -1;
1235     case GCONF_VALUE_LIST:
1236       {
1237         GSList *list_a;
1238         GSList *list_b;
1239 
1240         list_a = gconf_value_get_list (value_a);
1241         list_b = gconf_value_get_list (value_b);
1242 
1243         while (list_a != NULL && list_b != NULL)
1244           {
1245             int result;
1246 
1247             result = gconf_value_compare (list_a->data, list_b->data);
1248 
1249             if (result != 0)
1250               return result;
1251 
1252             list_a = g_slist_next (list_a);
1253             list_b = g_slist_next (list_b);
1254           }
1255 
1256         if (list_a)
1257           return 1; /* list_a is longer so "greater" */
1258         else if (list_b)
1259           return -1;
1260         else
1261           return 0;
1262       }
1263     case GCONF_VALUE_PAIR:
1264       {
1265         GConfValue *a_car, *b_car, *a_cdr, *b_cdr;
1266         int result;
1267 
1268         a_car = gconf_value_get_car (value_a);
1269         b_car = gconf_value_get_car (value_b);
1270         a_cdr = gconf_value_get_cdr (value_a);
1271         b_cdr = gconf_value_get_cdr (value_b);
1272 
1273         if (a_car == NULL && b_car != NULL)
1274           return -1;
1275         else if (a_car != NULL && b_car == NULL)
1276           return 1;
1277         else if (a_car != NULL && b_car != NULL)
1278           {
1279             result = gconf_value_compare (a_car, b_car);
1280 
1281             if (result != 0)
1282               return result;
1283           }
1284 
1285         if (a_cdr == NULL && b_cdr != NULL)
1286           return -1;
1287         else if (a_cdr != NULL && b_cdr == NULL)
1288           return 1;
1289         else if (a_cdr != NULL && b_cdr != NULL)
1290           {
1291             result = gconf_value_compare (a_cdr, b_cdr);
1292 
1293             if (result != 0)
1294               return result;
1295           }
1296 
1297         return 0;
1298       }
1299     case GCONF_VALUE_INVALID:
1300       return 0;
1301     case GCONF_VALUE_SCHEMA:
1302       {
1303         const char *locale_a, *locale_b;
1304         GConfValueType type_a, type_b;
1305         GConfValueType list_type_a, list_type_b;
1306         GConfValueType car_type_a, car_type_b;
1307         GConfValueType cdr_type_a, cdr_type_b;
1308         const char *short_desc_a, *short_desc_b;
1309         const char *long_desc_a, *long_desc_b;
1310         int result;
1311 
1312         type_a = gconf_schema_get_type (gconf_value_get_schema (value_a));
1313         type_b = gconf_schema_get_type (gconf_value_get_schema (value_b));
1314 
1315         if (type_a < type_b)
1316           return -1;
1317         else if (type_a > type_b)
1318           return 1;
1319 
1320         short_desc_a = gconf_schema_get_short_desc (gconf_value_get_schema (value_a));
1321         short_desc_b = gconf_schema_get_short_desc (gconf_value_get_schema (value_b));
1322 
1323         result = null_safe_strcmp (short_desc_a, short_desc_b);
1324         if (result != 0)
1325           return result;
1326 
1327         long_desc_a = gconf_schema_get_long_desc (gconf_value_get_schema (value_a));
1328 
1329 
1330         long_desc_b = gconf_schema_get_long_desc (gconf_value_get_schema (value_b));
1331 
1332         result = null_safe_strcmp (long_desc_a, long_desc_b);
1333         if (result != 0)
1334           return result;
1335 
1336         locale_a = gconf_schema_get_locale (gconf_value_get_schema (value_a));
1337         locale_b = gconf_schema_get_locale (gconf_value_get_schema (value_b));
1338 
1339         result = null_safe_strcmp (locale_a, locale_b);
1340         if (result != 0)
1341           return result;
1342 
1343         if (type_a == GCONF_VALUE_LIST)
1344           {
1345             list_type_a = gconf_schema_get_list_type (gconf_value_get_schema (value_a));
1346             list_type_b = gconf_schema_get_list_type (gconf_value_get_schema (value_b));
1347 
1348             if (list_type_a < list_type_b)
1349               return -1;
1350             else if (list_type_a > list_type_b)
1351               return 1;
1352           }
1353 
1354         if (type_a == GCONF_VALUE_PAIR)
1355           {
1356             car_type_a = gconf_schema_get_car_type (gconf_value_get_schema (value_a));
1357             car_type_b = gconf_schema_get_car_type (gconf_value_get_schema (value_b));
1358 
1359             if (car_type_a < car_type_b)
1360               return -1;
1361             else if (car_type_a > car_type_b)
1362               return 1;
1363 
1364             cdr_type_a = gconf_schema_get_cdr_type (gconf_value_get_schema (value_a));
1365             cdr_type_b = gconf_schema_get_cdr_type (gconf_value_get_schema (value_b));
1366 
1367             if (cdr_type_a < cdr_type_b)
1368               return -1;
1369             else if (cdr_type_a > cdr_type_b)
1370               return 1;
1371           }
1372 
1373         return 0;
1374       }
1375     }
1376 
1377   g_assert_not_reached ();
1378 
1379   return 0;
1380 }
1381 
1382 /*
1383  * GConfMetaInfo
1384  */
1385 
1386 GConfMetaInfo*
gconf_meta_info_new(void)1387 gconf_meta_info_new(void)
1388 {
1389   GConfMetaInfo* gcmi;
1390 
1391   gcmi = g_new0(GConfMetaInfo, 1);
1392 
1393   /* pointers and time are NULL/0 */
1394 
1395   return gcmi;
1396 }
1397 
1398 void
gconf_meta_info_free(GConfMetaInfo * gcmi)1399 gconf_meta_info_free(GConfMetaInfo* gcmi)
1400 {
1401   set_string(&gcmi->schema, NULL);
1402   set_string(&gcmi->mod_user, NULL);
1403   g_free(gcmi);
1404 }
1405 
1406 const char*
gconf_meta_info_get_schema(GConfMetaInfo * gcmi)1407 gconf_meta_info_get_schema (GConfMetaInfo *gcmi)
1408 {
1409   g_return_val_if_fail (gcmi != NULL, NULL);
1410 
1411   return gcmi->schema;
1412 }
1413 
1414 const char*
gconf_meta_info_get_mod_user(GConfMetaInfo * gcmi)1415 gconf_meta_info_get_mod_user (GConfMetaInfo *gcmi)
1416 {
1417   g_return_val_if_fail (gcmi != NULL, NULL);
1418 
1419   return gcmi->mod_user;
1420 }
1421 
1422 GTime
gconf_meta_info_mod_time(GConfMetaInfo * gcmi)1423 gconf_meta_info_mod_time (GConfMetaInfo *gcmi)
1424 {
1425   g_return_val_if_fail (gcmi != NULL, 0);
1426 
1427   return gcmi->mod_time;
1428 }
1429 
1430 void
gconf_meta_info_set_schema(GConfMetaInfo * gcmi,const gchar * schema_name)1431 gconf_meta_info_set_schema  (GConfMetaInfo* gcmi,
1432                               const gchar* schema_name)
1433 {
1434   set_string(&gcmi->schema, schema_name);
1435 }
1436 
1437 void
gconf_meta_info_set_mod_user(GConfMetaInfo * gcmi,const gchar * mod_user)1438 gconf_meta_info_set_mod_user(GConfMetaInfo* gcmi,
1439                               const gchar* mod_user)
1440 {
1441   set_string(&gcmi->mod_user, mod_user);
1442 }
1443 
1444 void
gconf_meta_info_set_mod_time(GConfMetaInfo * gcmi,GTime mod_time)1445 gconf_meta_info_set_mod_time(GConfMetaInfo* gcmi,
1446                               GTime mod_time)
1447 {
1448   gcmi->mod_time = mod_time;
1449 }
1450 
1451 /*
1452  * GConfEntry
1453  */
1454 
1455 typedef struct {
1456   char *key;
1457   GConfValue *value;
1458   char *schema_name;
1459   int refcount;
1460   guint is_default : 1;
1461   guint is_writable : 1;
1462 } GConfRealEntry;
1463 
1464 #define REAL_ENTRY(x) ((GConfRealEntry*)(x))
1465 
1466 GType
gconf_entry_get_type()1467 gconf_entry_get_type ()
1468 {
1469   static GType type = 0;
1470 
1471   if (type == 0)
1472     type = g_boxed_type_register_static (g_intern_static_string ("GConfEntry"),
1473                                          (GBoxedCopyFunc) gconf_entry_ref,
1474                                          (GBoxedFreeFunc) gconf_entry_unref);
1475   return type;
1476 }
1477 
1478 GConfEntry*
gconf_entry_new(const char * key,const GConfValue * val)1479 gconf_entry_new (const char *key,
1480                  const GConfValue  *val)
1481 {
1482   return gconf_entry_new_nocopy (g_strdup (key),
1483                                  val ? gconf_value_copy (val) : NULL);
1484 
1485 }
1486 
1487 GConfEntry*
gconf_entry_new_nocopy(char * key,GConfValue * val)1488 gconf_entry_new_nocopy (char* key, GConfValue* val)
1489 {
1490   GConfRealEntry* real;
1491 
1492   real = g_slice_new (GConfRealEntry);
1493 
1494   real->key   = key;
1495   real->value = val;
1496   real->schema_name = NULL;
1497   real->is_default = FALSE;
1498   real->is_writable = TRUE;
1499   real->refcount = 1;
1500 
1501   return (GConfEntry*) real;
1502 }
1503 
1504 GConfEntry *
gconf_entry_ref(GConfEntry * entry)1505 gconf_entry_ref (GConfEntry *entry)
1506 {
1507   g_return_val_if_fail (entry != NULL, NULL);
1508 
1509   REAL_ENTRY (entry)->refcount += 1;
1510 
1511   return entry;
1512 }
1513 
1514 void
gconf_entry_unref(GConfEntry * entry)1515 gconf_entry_unref (GConfEntry *entry)
1516 {
1517   GConfRealEntry *real;
1518 
1519   g_return_if_fail (entry != NULL);
1520   g_return_if_fail (REAL_ENTRY (entry)->refcount > 0);
1521 
1522   real = REAL_ENTRY (entry);
1523 
1524   real->refcount -= 1;
1525 
1526   if (real->refcount == 0)
1527     {
1528       g_free (real->key);
1529       if (real->value)
1530         gconf_value_free (real->value);
1531       g_free (real->schema_name);
1532       g_slice_free (GConfRealEntry, real);
1533     }
1534 }
1535 
1536 void
gconf_entry_free(GConfEntry * entry)1537 gconf_entry_free (GConfEntry *entry)
1538 {
1539   gconf_entry_unref (entry);
1540 }
1541 
1542 GConfEntry*
gconf_entry_copy(const GConfEntry * src)1543 gconf_entry_copy (const GConfEntry *src)
1544 {
1545   GConfEntry *entry;
1546   GConfRealEntry *real;
1547 
1548   entry = gconf_entry_new (REAL_ENTRY (src)->key,
1549                            REAL_ENTRY (src)->value);
1550   real = REAL_ENTRY (entry);
1551 
1552   real->schema_name = g_strdup (REAL_ENTRY (src)->schema_name);
1553   real->is_default = REAL_ENTRY (src)->is_default;
1554   real->is_writable = REAL_ENTRY (src)->is_writable;
1555 
1556   return entry;
1557 }
1558 
1559 gboolean
gconf_entry_equal(const GConfEntry * a,const GConfEntry * b)1560 gconf_entry_equal (const GConfEntry *a,
1561                    const GConfEntry *b)
1562 {
1563   GConfRealEntry *real_a;
1564   GConfRealEntry *real_b;
1565 
1566   g_return_val_if_fail (a != NULL, FALSE);
1567   g_return_val_if_fail (b != NULL, FALSE);
1568 
1569   real_a = REAL_ENTRY (a);
1570   real_b = REAL_ENTRY (b);
1571 
1572   /* do the cheap checks first, why not */
1573   if (real_a->value && !real_b->value)
1574     return FALSE;
1575   else if (!real_a->value && real_b->value)
1576     return FALSE;
1577   else if (real_a->is_default != real_b->is_default)
1578     return FALSE;
1579   else if (real_a->is_writable != real_b->is_writable)
1580     return FALSE;
1581   else if (strcmp (real_a->key, real_b->key) != 0)
1582     return FALSE;
1583   else if (real_a->schema_name && !real_b->schema_name)
1584     return FALSE;
1585   else if (!real_a->schema_name && real_b->schema_name)
1586     return FALSE;
1587   else if (real_a->schema_name && real_b->schema_name &&
1588            strcmp (real_a->schema_name, real_b->schema_name) != 0)
1589     return FALSE;
1590   else if (real_a->value && real_b->value &&
1591            gconf_value_compare (real_a->value, real_b->value) != 0)
1592     return FALSE;
1593   else
1594     return TRUE;
1595 }
1596 
1597 GConfValue*
gconf_entry_steal_value(GConfEntry * entry)1598 gconf_entry_steal_value (GConfEntry* entry)
1599 {
1600   GConfValue* val = REAL_ENTRY (entry)->value;
1601   REAL_ENTRY (entry)->value = NULL;
1602   return val;
1603 }
1604 
1605 const char*
gconf_entry_get_key(const GConfEntry * entry)1606 gconf_entry_get_key (const GConfEntry *entry)
1607 {
1608   g_return_val_if_fail (entry != NULL, NULL);
1609 
1610   return REAL_ENTRY (entry)->key;
1611 }
1612 
1613 GConfValue*
gconf_entry_get_value(const GConfEntry * entry)1614 gconf_entry_get_value (const GConfEntry *entry)
1615 {
1616   g_return_val_if_fail (entry != NULL, NULL);
1617 
1618   return REAL_ENTRY (entry)->value;
1619 }
1620 
1621 const char*
gconf_entry_get_schema_name(const GConfEntry * entry)1622 gconf_entry_get_schema_name (const GConfEntry *entry)
1623 {
1624   g_return_val_if_fail (entry != NULL, NULL);
1625 
1626   return REAL_ENTRY (entry)->schema_name;
1627 }
1628 
1629 gboolean
gconf_entry_get_is_default(const GConfEntry * entry)1630 gconf_entry_get_is_default  (const GConfEntry *entry)
1631 {
1632   g_return_val_if_fail (entry != NULL, FALSE);
1633 
1634   return REAL_ENTRY (entry)->is_default;
1635 }
1636 
1637 gboolean
gconf_entry_get_is_writable(const GConfEntry * entry)1638 gconf_entry_get_is_writable (const GConfEntry *entry)
1639 {
1640   g_return_val_if_fail (entry != NULL, FALSE);
1641 
1642   return REAL_ENTRY (entry)->is_writable;
1643 }
1644 
1645 
1646 void
gconf_entry_set_value(GConfEntry * entry,const GConfValue * val)1647 gconf_entry_set_value (GConfEntry  *entry,
1648                        const GConfValue  *val)
1649 {
1650   gconf_entry_set_value_nocopy (entry,
1651                                 val ? gconf_value_copy (val) : NULL);
1652 }
1653 
1654 void
gconf_entry_set_value_nocopy(GConfEntry * entry,GConfValue * val)1655 gconf_entry_set_value_nocopy(GConfEntry* entry,
1656                              GConfValue* val)
1657 {
1658   if (REAL_ENTRY (entry)->value)
1659     gconf_value_free (REAL_ENTRY (entry)->value);
1660 
1661   REAL_ENTRY (entry)->value = val;
1662 }
1663 
1664 void
gconf_entry_set_schema_name(GConfEntry * entry,const gchar * name)1665 gconf_entry_set_schema_name(GConfEntry* entry,
1666                             const gchar* name)
1667 {
1668   g_free (REAL_ENTRY (entry)->schema_name);
1669 
1670   REAL_ENTRY (entry)->schema_name = g_strdup(name);
1671 }
1672 
1673 void
gconf_entry_set_is_default(GConfEntry * entry,gboolean is_default)1674 gconf_entry_set_is_default (GConfEntry* entry,
1675                             gboolean is_default)
1676 {
1677   REAL_ENTRY (entry)->is_default = is_default;
1678 }
1679 
1680 void
gconf_entry_set_is_writable(GConfEntry * entry,gboolean is_writable)1681 gconf_entry_set_is_writable (GConfEntry  *entry,
1682                              gboolean     is_writable)
1683 {
1684   REAL_ENTRY (entry)->is_writable = is_writable;
1685 }
1686 
1687 
1688 gboolean
gconf_value_validate(const GConfValue * value,GError ** err)1689 gconf_value_validate (const GConfValue *value,
1690                       GError          **err)
1691 {
1692   GConfRealValue *real;
1693 
1694   g_return_val_if_fail (value != NULL, FALSE);
1695 
1696   real = REAL_VALUE (value);
1697 
1698   switch (value->type)
1699     {
1700     case GCONF_VALUE_STRING:
1701       if (real->d.string_data &&
1702           !g_utf8_validate (real->d.string_data, -1, NULL))
1703         {
1704           g_set_error (err, GCONF_ERROR,
1705                        GCONF_ERROR_FAILED,
1706                        _("Text contains invalid UTF-8"));
1707           return FALSE;
1708         }
1709       break;
1710 
1711     case GCONF_VALUE_SCHEMA:
1712       if (real->d.schema_data)
1713         return gconf_schema_validate (real->d.schema_data,
1714                                       err);
1715       break;
1716 
1717     default:
1718       break;
1719     }
1720 
1721   return TRUE;
1722 }
1723