source: trunk/third/GConf/gconf/gconf-internals.c @ 15964

Revision 15964, 58.8 KB checked in by ghudson, 23 years ago (diff)
Merge with GConf 1.0.0.
Line 
1
2/* GConf
3 * Copyright (C) 1999, 2000 Red Hat Inc.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
19 */
20
21#include <config.h>
22#include "gconf-internals.h"
23#include "gconf-backend.h"
24#include "gconf-schema.h"
25#include <orb/orbit.h>
26#include <liboaf/liboaf.h>
27#include <string.h>
28#include <sys/stat.h>
29#include <sys/types.h>
30#include <unistd.h>
31#include <stdlib.h>
32#include <stdio.h>
33#include <fcntl.h>
34#include <errno.h>
35#include <ctype.h>
36#include <locale.h>
37#include <time.h>
38#include <math.h>
39
40static gboolean gconf_daemon_mode = FALSE;
41static gchar* daemon_ior = NULL;
42
43void
44gconf_set_daemon_mode(gboolean setting)
45{
46  gconf_daemon_mode = setting;
47}
48
49gboolean
50gconf_in_daemon_mode(void)
51{
52  return gconf_daemon_mode;
53}
54
55void
56gconf_set_daemon_ior(const gchar* ior)
57{
58  if (daemon_ior != NULL)
59    {
60      g_free(daemon_ior);
61      daemon_ior = NULL;
62    }
63     
64  if (ior != NULL)
65    daemon_ior = g_strdup(ior);
66}
67
68const gchar*
69gconf_get_daemon_ior(void)
70{
71  return daemon_ior;
72}
73
74gchar*
75gconf_key_directory  (const gchar* key)
76{
77  const gchar* end;
78  gchar* retval;
79  int len;
80
81  end = strrchr(key, '/');
82
83  if (end == NULL)
84    {
85      gconf_log(GCL_ERR, _("No '/' in key `%s'"), key);
86      return NULL;
87    }
88
89  len = end-key+1;
90
91  if (len == 1)
92    {
93      /* Root directory */
94      retval = g_strdup("/");
95    }
96  else
97    {
98      retval = g_malloc(len);
99     
100      strncpy(retval, key, len);
101     
102      retval[len-1] = '\0';
103    }
104
105  return retval;
106}
107
108const gchar*
109gconf_key_key        (const gchar* key)
110{
111  const gchar* end;
112 
113  end = strrchr(key, '/');
114
115  ++end;
116
117  return end;
118}
119
120/*
121 *  Random stuff
122 */
123
124gboolean
125gconf_file_exists (const gchar* filename)
126{
127  struct stat s;
128 
129  g_return_val_if_fail (filename != NULL,FALSE);
130 
131  return stat (filename, &s) == 0;
132}
133
134gboolean
135gconf_file_test(const gchar* filename, int test)
136{
137  struct stat s;
138  if(stat (filename, &s) != 0)
139    return FALSE;
140  if(!(test & GCONF_FILE_ISFILE) && S_ISREG(s.st_mode))
141    return FALSE;
142  if(!(test & GCONF_FILE_ISLINK) && S_ISLNK(s.st_mode))
143    return FALSE;
144  if(!(test & GCONF_FILE_ISDIR) && S_ISDIR(s.st_mode))
145    return FALSE;
146  return TRUE;
147}
148
149GConfValue*
150gconf_value_from_corba_value(const ConfigValue* value)
151{
152  GConfValue* gval;
153  GConfValueType type = GCONF_VALUE_INVALID;
154 
155  switch (value->_d)
156    {
157    case InvalidVal:
158      return NULL;
159      break;
160    case IntVal:
161      type = GCONF_VALUE_INT;
162      break;
163    case StringVal:
164      type = GCONF_VALUE_STRING;
165      break;
166    case FloatVal:
167      type = GCONF_VALUE_FLOAT;
168      break;
169    case BoolVal:
170      type = GCONF_VALUE_BOOL;
171      break;
172    case SchemaVal:
173      type = GCONF_VALUE_SCHEMA;
174      break;
175    case ListVal:
176      type = GCONF_VALUE_LIST;
177      break;
178    case PairVal:
179      type = GCONF_VALUE_PAIR;
180      break;
181    default:
182      gconf_log(GCL_DEBUG, "Invalid type in %s", G_GNUC_FUNCTION);
183      return NULL;
184    }
185
186  g_assert(GCONF_VALUE_TYPE_VALID(type));
187 
188  gval = gconf_value_new(type);
189
190  switch (gval->type)
191    {
192    case GCONF_VALUE_INT:
193      gconf_value_set_int(gval, value->_u.int_value);
194      break;
195    case GCONF_VALUE_STRING:
196      gconf_value_set_string(gval, value->_u.string_value);
197      break;
198    case GCONF_VALUE_FLOAT:
199      gconf_value_set_float(gval, value->_u.float_value);
200      break;
201    case GCONF_VALUE_BOOL:
202      gconf_value_set_bool(gval, value->_u.bool_value);
203      break;
204    case GCONF_VALUE_SCHEMA:
205      gconf_value_set_schema_nocopy(gval,
206                                    gconf_schema_from_corba_schema(&(value->_u.schema_value)));
207      break;
208    case GCONF_VALUE_LIST:
209      {
210        GSList* list = NULL;
211        guint i = 0;
212       
213        switch (value->_u.list_value.list_type)
214          {
215          case BIntVal:
216            gconf_value_set_list_type(gval, GCONF_VALUE_INT);
217            break;
218          case BBoolVal:
219            gconf_value_set_list_type(gval, GCONF_VALUE_BOOL);
220            break;
221          case BFloatVal:
222            gconf_value_set_list_type(gval, GCONF_VALUE_FLOAT);
223            break;
224          case BStringVal:
225            gconf_value_set_list_type(gval, GCONF_VALUE_STRING);
226            break;
227          case BInvalidVal:
228            break;
229          default:
230            g_warning("Bizarre list type in %s", G_GNUC_FUNCTION);
231            break;
232          }
233
234        if (gconf_value_get_list_type(gval) != GCONF_VALUE_INVALID)
235          {
236            i = 0;
237            while (i < value->_u.list_value.seq._length)
238              {
239                GConfValue* val;
240               
241                /* This is a bit dubious; we cast a ConfigBasicValue to ConfigValue
242                   because they have the same initial members, but by the time
243                   the CORBA and C specs kick in, not sure we are guaranteed
244                   to be able to do this.
245                */
246                val = gconf_value_from_corba_value((ConfigValue*)&value->_u.list_value.seq._buffer[i]);
247               
248                if (val == NULL)
249                  gconf_log(GCL_ERR, _("Couldn't interpret CORBA value for list element"));
250                else if (val->type != gconf_value_get_list_type(gval))
251                  gconf_log(GCL_ERR, _("Incorrect type for list element in %s"), G_GNUC_FUNCTION);
252                else
253                  list = g_slist_prepend(list, val);
254               
255                ++i;
256              }
257       
258            list = g_slist_reverse(list);
259           
260            gconf_value_set_list_nocopy(gval, list);
261          }
262        else
263          {
264            gconf_log(GCL_ERR, _("Received list from gconfd with a bad list type"));
265          }
266      }
267      break;
268    case GCONF_VALUE_PAIR:
269      {
270        g_return_val_if_fail(value->_u.pair_value._length == 2, gval);
271       
272        gconf_value_set_car_nocopy(gval,
273                                   gconf_value_from_corba_value((ConfigValue*)&value->_u.list_value.seq._buffer[0]));
274
275        gconf_value_set_cdr_nocopy(gval,
276                                   gconf_value_from_corba_value((ConfigValue*)&value->_u.list_value.seq._buffer[1]));
277      }
278      break;
279    default:
280      g_assert_not_reached();
281      break;
282    }
283 
284  return gval;
285}
286
287void         
288fill_corba_value_from_gconf_value(GConfValue* value,
289                                   ConfigValue* cv)
290{
291  if (value == NULL)
292    {
293      cv->_d = InvalidVal;
294      return;
295    }
296
297  switch (value->type)
298    {
299    case GCONF_VALUE_INT:
300      cv->_d = IntVal;
301      cv->_u.int_value = gconf_value_get_int(value);
302      break;
303    case GCONF_VALUE_STRING:
304      cv->_d = StringVal;
305      cv->_u.string_value = CORBA_string_dup((char*)gconf_value_get_string(value));
306      break;
307    case GCONF_VALUE_FLOAT:
308      cv->_d = FloatVal;
309      cv->_u.float_value = gconf_value_get_float(value);
310      break;
311    case GCONF_VALUE_BOOL:
312      cv->_d = BoolVal;
313      cv->_u.bool_value = gconf_value_get_bool(value);
314      break;
315    case GCONF_VALUE_SCHEMA:
316      cv->_d = SchemaVal;
317      fill_corba_schema_from_gconf_schema(gconf_value_get_schema(value),
318                                           &cv->_u.schema_value);
319      break;
320    case GCONF_VALUE_LIST:
321      {
322        guint n, i;
323        GSList* list;
324       
325        cv->_d = ListVal;
326
327        list = gconf_value_get_list(value);
328
329        n = g_slist_length(list);
330
331        cv->_u.list_value.seq._buffer =
332          CORBA_sequence_ConfigBasicValue_allocbuf(n);
333        cv->_u.list_value.seq._length = n;
334        cv->_u.list_value.seq._maximum = n;
335        CORBA_sequence_set_release(&cv->_u.list_value.seq, TRUE);
336       
337        switch (gconf_value_get_list_type(value))
338          {
339          case GCONF_VALUE_INT:
340            cv->_u.list_value.list_type = BIntVal;
341            break;
342
343          case GCONF_VALUE_BOOL:
344            cv->_u.list_value.list_type = BBoolVal;
345            break;
346           
347          case GCONF_VALUE_STRING:
348            cv->_u.list_value.list_type = BStringVal;
349            break;
350
351          case GCONF_VALUE_FLOAT:
352            cv->_u.list_value.list_type = BFloatVal;
353            break;
354
355          case GCONF_VALUE_SCHEMA:
356            cv->_u.list_value.list_type = BSchemaVal;
357            break;
358           
359          default:
360            cv->_u.list_value.list_type = BInvalidVal;
361            gconf_log(GCL_DEBUG, "Invalid list type in %s", G_GNUC_FUNCTION);
362            break;
363          }
364       
365        i= 0;
366        while (list != NULL)
367          {
368            /* That dubious ConfigBasicValue->ConfigValue cast again */
369            fill_corba_value_from_gconf_value((GConfValue*)list->data,
370                                               (ConfigValue*)&cv->_u.list_value.seq._buffer[i]);
371
372            list = g_slist_next(list);
373            ++i;
374          }
375      }
376      break;
377    case GCONF_VALUE_PAIR:
378      {
379        cv->_d = PairVal;
380
381        cv->_u.pair_value._buffer =
382          CORBA_sequence_ConfigBasicValue_allocbuf(2);
383        cv->_u.pair_value._length = 2;
384        cv->_u.pair_value._maximum = 2;
385        CORBA_sequence_set_release(&cv->_u.pair_value, TRUE);
386       
387        /* dubious cast */
388        fill_corba_value_from_gconf_value(gconf_value_get_car(value),
389                                           (ConfigValue*)&cv->_u.pair_value._buffer[0]);
390        fill_corba_value_from_gconf_value(gconf_value_get_cdr(value),
391                                           (ConfigValue*)&cv->_u.pair_value._buffer[1]);
392      }
393      break;
394     
395    case GCONF_VALUE_INVALID:
396      cv->_d = InvalidVal;
397      break;
398    default:
399      cv->_d = InvalidVal;
400      gconf_log(GCL_DEBUG, "Unknown type in %s", G_GNUC_FUNCTION);
401      break;
402    }
403}
404
405ConfigValue* 
406corba_value_from_gconf_value(GConfValue* value)
407{
408  ConfigValue* cv;
409
410  cv = ConfigValue__alloc();
411
412  fill_corba_value_from_gconf_value(value, cv);
413
414  return cv;
415}
416
417ConfigValue* 
418invalid_corba_value()
419{
420  ConfigValue* cv;
421
422  cv = ConfigValue__alloc();
423
424  cv->_d = InvalidVal;
425
426  return cv;
427}
428
429gchar*
430gconf_object_to_string (CORBA_Object obj,
431                        GError **err)
432{
433  CORBA_Environment ev;
434  gchar *ior;
435  gchar *retval;
436 
437  CORBA_exception_init (&ev);
438
439  ior = CORBA_ORB_object_to_string (oaf_orb_get (), obj, &ev);
440
441  if (ior == NULL)
442    {
443      gconf_set_error (err,
444                       GCONF_ERROR_FAILED,
445                       _("Failed to convert object to IOR"));
446
447      return NULL;
448    }
449
450  retval = g_strdup (ior);
451
452  CORBA_free (ior);
453
454  return retval;
455}
456
457static ConfigValueType
458corba_type_from_gconf_type(GConfValueType type)
459{
460  switch (type)
461    {
462    case GCONF_VALUE_INT:
463      return IntVal;
464    case GCONF_VALUE_BOOL:
465      return BoolVal;
466    case GCONF_VALUE_FLOAT:
467      return FloatVal;
468    case GCONF_VALUE_INVALID:
469      return InvalidVal;
470    case GCONF_VALUE_STRING:
471      return StringVal;
472    case GCONF_VALUE_SCHEMA:
473      return SchemaVal;
474    case GCONF_VALUE_LIST:
475      return ListVal;
476    case GCONF_VALUE_PAIR:
477      return PairVal;
478    default:
479      g_assert_not_reached();
480      return InvalidVal;
481    }
482}
483
484static GConfValueType
485gconf_type_from_corba_type(ConfigValueType type)
486{
487  switch (type)
488    {
489    case InvalidVal:
490      return GCONF_VALUE_INVALID;
491    case StringVal:
492      return GCONF_VALUE_STRING;
493    case IntVal:
494      return GCONF_VALUE_INT;
495    case FloatVal:
496      return GCONF_VALUE_FLOAT;
497    case SchemaVal:
498      return GCONF_VALUE_SCHEMA;
499    case BoolVal:
500      return GCONF_VALUE_BOOL;
501    case ListVal:
502      return GCONF_VALUE_LIST;
503    case PairVal:
504      return GCONF_VALUE_PAIR;
505    default:
506      g_assert_not_reached();
507      return GCONF_VALUE_INVALID;
508    }
509}
510
511void         
512fill_corba_schema_from_gconf_schema(GConfSchema* sc,
513                                     ConfigSchema* cs)
514{
515  cs->value_type = corba_type_from_gconf_type(sc->type);
516  cs->value_list_type = corba_type_from_gconf_type(sc->list_type);
517  cs->value_car_type = corba_type_from_gconf_type(sc->car_type);
518  cs->value_cdr_type = corba_type_from_gconf_type(sc->cdr_type);
519
520  cs->locale = CORBA_string_dup(sc->locale ? sc->locale : "");
521  cs->short_desc = CORBA_string_dup(sc->short_desc ? sc->short_desc : "");
522  cs->long_desc = CORBA_string_dup(sc->long_desc ? sc->long_desc : "");
523  cs->owner = CORBA_string_dup(sc->owner ? sc->owner : "");
524
525  {
526    gchar* encoded;
527    GConfValue* default_val;
528
529    default_val = gconf_schema_get_default_value(sc);
530
531    if (default_val)
532      {
533        encoded = gconf_value_encode(default_val);
534
535        g_assert(encoded != NULL);
536
537        cs->encoded_default_value = CORBA_string_dup(encoded);
538
539        g_free(encoded);
540      }
541    else
542      cs->encoded_default_value = CORBA_string_dup("");
543  }
544}
545
546ConfigSchema*
547corba_schema_from_gconf_schema(GConfSchema* sc)
548{
549  ConfigSchema* cs;
550
551  cs = ConfigSchema__alloc();
552
553  fill_corba_schema_from_gconf_schema(sc, cs);
554
555  return cs;
556}
557
558GConfSchema* 
559gconf_schema_from_corba_schema(const ConfigSchema* cs)
560{
561  GConfSchema* sc;
562  GConfValueType type = GCONF_VALUE_INVALID;
563  GConfValueType list_type = GCONF_VALUE_INVALID;
564  GConfValueType car_type = GCONF_VALUE_INVALID;
565  GConfValueType cdr_type = GCONF_VALUE_INVALID;
566
567  type = gconf_type_from_corba_type(cs->value_type);
568  list_type = gconf_type_from_corba_type(cs->value_list_type);
569  car_type = gconf_type_from_corba_type(cs->value_car_type);
570  cdr_type = gconf_type_from_corba_type(cs->value_cdr_type);
571
572  sc = gconf_schema_new();
573
574  gconf_schema_set_type(sc, type);
575  gconf_schema_set_list_type(sc, list_type);
576  gconf_schema_set_car_type(sc, car_type);
577  gconf_schema_set_cdr_type(sc, cdr_type);
578
579  if (*cs->locale != '\0')
580    gconf_schema_set_locale(sc, cs->locale);
581
582  if (*cs->short_desc != '\0')
583    gconf_schema_set_short_desc(sc, cs->short_desc);
584
585  if (*cs->long_desc != '\0')
586    gconf_schema_set_long_desc(sc, cs->long_desc);
587
588  if (*cs->owner != '\0')
589    gconf_schema_set_owner(sc, cs->owner);
590
591  {
592    GConfValue* val;
593
594    val = gconf_value_decode(cs->encoded_default_value);
595
596    if (val)
597      gconf_schema_set_default_value_nocopy(sc, val);
598  }
599 
600  return sc;
601}
602
603const gchar*
604gconf_value_type_to_string(GConfValueType type)
605{
606  switch (type)
607    {
608    case GCONF_VALUE_INT:
609      return "int";
610      break;
611    case GCONF_VALUE_STRING:
612      return "string";
613      break;
614    case GCONF_VALUE_FLOAT:
615      return "float";
616      break;
617    case GCONF_VALUE_BOOL:
618      return "bool";
619      break;
620    case GCONF_VALUE_SCHEMA:
621      return "schema";
622      break;
623    case GCONF_VALUE_LIST:
624      return "list";
625      break;
626    case GCONF_VALUE_PAIR:
627      return "pair";
628      break;
629    case GCONF_VALUE_INVALID:
630      return "*invalid*";
631      break;
632    default:
633      g_assert_not_reached();
634      return NULL; /* for warnings */
635      break;
636    }
637}
638
639GConfValueType
640gconf_value_type_from_string(const gchar* type_str)
641{
642  if (strcmp(type_str, "int") == 0)
643    return GCONF_VALUE_INT;
644  else if (strcmp(type_str, "float") == 0)
645    return GCONF_VALUE_FLOAT;
646  else if (strcmp(type_str, "string") == 0)
647    return GCONF_VALUE_STRING;
648  else if (strcmp(type_str, "bool") == 0)
649    return GCONF_VALUE_BOOL;
650  else if (strcmp(type_str, "schema") == 0)
651    return GCONF_VALUE_SCHEMA;
652  else if (strcmp(type_str, "list") == 0)
653    return GCONF_VALUE_LIST;
654  else if (strcmp(type_str, "pair") == 0)
655    return GCONF_VALUE_PAIR;
656  else
657    return GCONF_VALUE_INVALID;
658}
659
660/*
661 * Config files (yikes! we can't store our config in GConf!)
662 */
663
664static gchar*
665unquote_string(gchar* s)
666{
667  gchar* end;
668
669  /* Strip whitespace and first quote from front of string */
670  while (*s && (isspace(*s) || (*s == '"')))
671    ++s;
672
673  end = s;
674  while (*end)
675    ++end;
676
677  --end; /* one back from '\0' */
678
679  /* Strip whitespace and last quote from end of string */
680  while ((end > s) && (isspace(*end) || (*end == '"')))
681    {
682      *end = '\0';
683      --end;
684    }
685
686  return s;
687}
688
689static const gchar*
690get_variable(const gchar* varname)
691{
692  /* These first two DO NOT use environment variables, which
693     makes things a bit more "secure" in some sense
694  */
695  if (strcmp(varname, "HOME") == 0)
696    {
697      return g_get_home_dir();
698    }
699  else if (strcmp(varname, "USER") == 0)
700    {
701      return g_get_user_name();
702    }
703  else if (varname[0] == 'E' &&
704           varname[1] == 'N' &&
705           varname[2] == 'V' &&
706           varname[3] == '_')
707    {
708      /* This is magic: if a variable called ENV_FOO is used,
709         then the environment variable FOO is checked */
710      gchar* envvar = getenv(&varname[4]);
711
712      if (envvar)
713        return envvar;
714      else
715        return "";
716    }
717  else
718    return "";
719}
720
721static gchar*
722subst_variables(const gchar* src)
723{
724  const gchar* iter;
725  gchar* retval;
726  guint retval_len;
727  guint pos;
728 
729  g_return_val_if_fail(src != NULL, NULL);
730
731  retval_len = strlen(src) + 1;
732  pos = 0;
733 
734  retval = g_malloc0(retval_len+3); /* add 3 just to avoid off-by-one
735                                       segvs - yeah I know it bugs
736                                       you, but C sucks */
737 
738  iter = src;
739
740  while (*iter)
741    {
742      gboolean performed_subst = FALSE;
743     
744      if (pos >= retval_len)
745        {
746          retval_len *= 2;
747          retval = g_realloc(retval, retval_len+3); /* add 3 for luck */
748        }
749     
750      if (*iter == '$' && *(iter+1) == '(')
751        {
752          const gchar* varstart = iter + 2;
753          const gchar* varend   = strchr(varstart, ')');
754
755          if (varend != NULL)
756            {
757              char* varname;
758              const gchar* varval;
759              guint varval_len;
760
761              performed_subst = TRUE;
762
763              varname = g_strndup(varstart, varend - varstart);
764             
765              varval = get_variable(varname);
766              g_free(varname);
767
768              varval_len = strlen(varval);
769
770              if ((retval_len - pos) < varval_len)
771                {
772                  retval_len *= 2;
773                  retval = g_realloc(retval, retval_len+3);
774                }
775             
776              strcpy(&retval[pos], varval);
777              pos += varval_len;
778
779              iter = varend + 1;
780            }
781        }
782
783      if (!performed_subst)
784        {
785          retval[pos] = *iter;
786          ++pos;
787          ++iter;
788        }
789    }
790  retval[pos] = '\0';
791
792  return retval;
793}
794
795gchar**       
796gconf_load_source_path(const gchar* filename, GError** err)
797{
798  FILE* f;
799  GSList* l = NULL;
800  gchar** addresses;
801  gchar buf[512];
802  GSList* tmp;
803  guint n;
804
805  f = fopen(filename, "r");
806
807  if (f == NULL)
808    {
809      if (err)
810        *err = gconf_error_new(GCONF_ERROR_FAILED,
811                                _("Couldn't open path file `%s': %s\n"),
812                                filename,
813                                strerror(errno));
814      return NULL;
815    }
816
817  while (fgets(buf, 512, f) != NULL)
818    {
819      gchar* s = buf;
820     
821      while (*s && isspace(*s))
822        ++s;
823
824      if (*s == '#')
825        {
826          /* Allow comments, why not */
827        }
828      else if (*s == '\0')
829        {
830          /* Blank line */
831        }
832      else if (strncmp("include", s, 7) == 0)
833        {
834          gchar* unq;
835          gchar** included;
836
837          s += 7;
838
839          unq = unquote_string(s);
840
841          included = gconf_load_source_path(unq, NULL);
842
843          if (included != NULL)
844            {
845              gchar** iter = included;
846
847              while (*iter)
848                {
849                  l = g_slist_prepend(l, *iter); /* Note that we won't free *included */
850                  ++iter;
851                }
852
853              g_free(included); /* Only the array, not the contained strings */
854            }
855        }
856      else
857        {
858          gchar* unq;
859          gchar* varsubst;
860         
861          unq = unquote_string(buf);
862          varsubst = subst_variables(unq);
863         
864          if (*varsubst != '\0') /* Drop lines with just two quote marks or something */
865            {
866              gconf_log(GCL_INFO, _("Adding source `%s'\n"), varsubst);
867              l = g_slist_prepend(l, g_strdup(varsubst));
868            }
869          g_free(varsubst);
870        }
871    }
872
873  if (ferror(f))
874    {
875      /* This should basically never happen */
876      if (err)
877        *err = gconf_error_new(GCONF_ERROR_FAILED,
878                                _("Read error on file `%s': %s\n"),
879                                filename,
880                                strerror(errno));
881      /* don't return, we want to go ahead and return any
882         addresses we already loaded. */
883    }
884
885  fclose(f); 
886
887  /* This will make sense if you realize that we reversed the list
888     as we loaded it, and are now reversing it to be correct again.
889  */
890
891  if (l == NULL)
892    return NULL;
893
894  n = g_slist_length(l);
895
896  g_assert(n > 0);
897 
898  addresses = g_malloc0(sizeof(gchar*) * (n+1));
899
900  addresses[n] = NULL;
901
902  --n;
903  tmp = l;
904
905  while (tmp != NULL)
906    {
907      addresses[n] = tmp->data;
908
909      tmp = g_slist_next(tmp);
910      --n;
911    }
912 
913  g_assert(addresses[0] != NULL); /* since we used malloc0 this detects bad logic */
914
915  return addresses;
916}
917
918/* This should also support concatting filesystem dirs and keys,
919   or dir and subdir.
920*/
921gchar*       
922gconf_concat_dir_and_key(const gchar* dir, const gchar* key)
923{
924  guint dirlen;
925  guint keylen;
926  gchar* retval;
927
928  g_return_val_if_fail(dir != NULL, NULL);
929  g_return_val_if_fail(key != NULL, NULL);
930  g_return_val_if_fail(*dir == '/', NULL);
931
932  dirlen = strlen(dir);
933  keylen = strlen(key);
934
935  retval = g_malloc0(dirlen+keylen+3); /* auto-null-terminate */
936
937  strcpy(retval, dir);
938
939  if (dir[dirlen-1] == '/')
940    {
941      /* dir ends in slash, strip key slash if needed */
942      if (*key == '/')
943        ++key;
944
945      strcpy((retval+dirlen), key);
946    }
947  else
948    {
949      /* Dir doesn't end in slash, add slash if key lacks one. */
950      gchar* dest = retval + dirlen;
951
952      if (*key != '/')
953        {
954          *dest = '/';
955          ++dest;
956        }
957     
958      strcpy(dest, key);
959    }
960 
961  return retval;
962}
963
964gulong
965gconf_string_to_gulong(const gchar* str)
966{
967  gulong retval;
968  gchar *end;
969  errno = 0;
970  retval = strtoul(str, &end, 10);
971  if (end == str || errno != 0)
972    retval = 0;
973
974  return retval;
975}
976
977gboolean
978gconf_string_to_double(const gchar* str, gdouble* retloc)
979{
980  int res;
981  char *old_locale;
982
983  /* make sure we write values to files in a consistent manner */
984  old_locale = g_strdup (setlocale (LC_NUMERIC, NULL));
985  setlocale (LC_NUMERIC, "C");
986
987  *retloc = 0.0;
988  res = sscanf (str, "%lf", retloc);
989
990  setlocale (LC_NUMERIC, old_locale);
991  g_free (old_locale);
992
993  if (res == 1)
994    return TRUE;
995  else
996    return FALSE;
997}
998
999gchar*
1000gconf_double_to_string(gdouble val)
1001{
1002  char str[101 + DBL_DIG];
1003  char *old_locale;
1004
1005  /* make sure we write values to files in a consistent manner */
1006  old_locale = g_strdup (setlocale (LC_NUMERIC, NULL));
1007  setlocale (LC_NUMERIC, "C");
1008 
1009  if (fabs (val) < 1e9 && fabs (val) > 1e-5)
1010    snprintf (str, 100 + DBL_DIG, "%.*g", DBL_DIG, val);
1011  else
1012    snprintf (str, 100 + DBL_DIG, "%f", val);
1013
1014  setlocale (LC_NUMERIC, old_locale);
1015  g_free (old_locale);
1016 
1017  return g_strdup(str);
1018}
1019
1020const gchar*
1021gconf_current_locale(void)
1022{
1023#ifdef HAVE_LC_MESSAGES
1024  return setlocale(LC_MESSAGES, NULL);
1025#else
1026  return setlocale(LC_CTYPE, NULL);
1027#endif
1028}
1029
1030/*
1031 * Log
1032 */
1033
1034gchar*
1035gconf_quote_percents(const gchar* src)
1036{
1037  gchar* dest;
1038  const gchar* s;
1039  gchar* d;
1040
1041  g_return_val_if_fail(src != NULL, NULL);
1042 
1043  /* waste memory! woo-hoo! */
1044  dest = g_malloc0(strlen(src)*2+4);
1045 
1046  d = dest;
1047 
1048  s = src;
1049  while (*s)
1050    {
1051      switch (*s)
1052        {
1053        case '%':
1054          {
1055            *d = '%';
1056            ++d;
1057            *d = '%';
1058            ++d;
1059          }
1060          break;
1061         
1062        default:
1063          {
1064            *d = *s;
1065            ++d;
1066          }
1067          break;
1068        }
1069      ++s;
1070    }
1071
1072  /* End with NULL */
1073  *d = '\0';
1074 
1075  return dest;
1076}
1077
1078#include <syslog.h>
1079
1080void
1081gconf_log(GConfLogPriority pri, const gchar* fmt, ...)
1082{
1083  gchar* msg;
1084  va_list args;
1085  int syslog_pri = LOG_DEBUG;
1086
1087#ifndef GCONF_ENABLE_DEBUG
1088  if (pri == GCL_DEBUG)
1089    return;
1090#endif
1091 
1092  va_start (args, fmt);
1093  msg = g_strdup_vprintf(fmt, args);
1094  va_end (args);
1095
1096  if (gconf_daemon_mode)
1097    {
1098      switch (pri)
1099        {
1100        case GCL_EMERG:
1101          syslog_pri = LOG_EMERG;
1102          break;
1103     
1104        case GCL_ALERT:
1105          syslog_pri = LOG_ALERT;
1106          break;
1107     
1108        case GCL_CRIT:
1109          syslog_pri = LOG_CRIT;
1110          break;
1111     
1112        case GCL_ERR:
1113          syslog_pri = LOG_ERR;
1114          break;
1115     
1116        case GCL_WARNING:
1117          syslog_pri = LOG_WARNING;
1118          break;
1119     
1120        case GCL_NOTICE:
1121          syslog_pri = LOG_NOTICE;
1122          break;
1123     
1124        case GCL_INFO:
1125          syslog_pri = LOG_INFO;
1126          break;
1127     
1128        case GCL_DEBUG:
1129          syslog_pri = LOG_DEBUG;
1130          break;
1131
1132        default:
1133          g_assert_not_reached();
1134          break;
1135        }
1136
1137      syslog(syslog_pri, "%s", msg);
1138    }
1139  else
1140    {
1141      switch (pri)
1142        {
1143        case GCL_EMERG:
1144        case GCL_ALERT:
1145        case GCL_CRIT:
1146        case GCL_ERR:
1147        case GCL_WARNING:
1148          fprintf(stderr, "%s\n", msg);
1149          break;
1150     
1151        case GCL_NOTICE:
1152        case GCL_INFO:
1153        case GCL_DEBUG:
1154          printf("%s\n", msg);
1155          break;
1156
1157        default:
1158          g_assert_not_reached();
1159          break;
1160        }
1161    }
1162 
1163  g_free(msg);
1164}
1165
1166/*
1167 * List/pair conversion
1168 */
1169
1170GConfValue*
1171gconf_value_list_from_primitive_list(GConfValueType list_type, GSList* list)
1172{
1173  GSList* value_list;
1174  GSList* tmp;
1175
1176  g_return_val_if_fail(list_type != GCONF_VALUE_INVALID, NULL);
1177  g_return_val_if_fail(list_type != GCONF_VALUE_LIST, NULL);
1178  g_return_val_if_fail(list_type != GCONF_VALUE_PAIR, NULL);
1179 
1180  value_list = NULL;
1181
1182  tmp = list;
1183
1184  while (tmp != NULL)
1185    {
1186      GConfValue* val;
1187
1188      val = gconf_value_new(list_type);
1189
1190      switch (list_type)
1191        {
1192        case GCONF_VALUE_INT:
1193          gconf_value_set_int(val, GPOINTER_TO_INT(tmp->data));
1194          break;
1195
1196        case GCONF_VALUE_BOOL:
1197          gconf_value_set_bool(val, GPOINTER_TO_INT(tmp->data));
1198          break;
1199
1200        case GCONF_VALUE_FLOAT:
1201          gconf_value_set_float(val, *((gdouble*)tmp->data));
1202          break;
1203
1204        case GCONF_VALUE_STRING:
1205          gconf_value_set_string(val, tmp->data);
1206          break;
1207
1208        case GCONF_VALUE_SCHEMA:
1209          gconf_value_set_schema(val, tmp->data);
1210          break;
1211         
1212        default:
1213          g_assert_not_reached();
1214          break;
1215        }
1216
1217      value_list = g_slist_prepend(value_list, val);
1218
1219      tmp = g_slist_next(tmp);
1220    }
1221
1222  /* Get it in the right order. */
1223  value_list = g_slist_reverse(value_list);
1224
1225  {
1226    GConfValue* value_with_list;
1227   
1228    value_with_list = gconf_value_new(GCONF_VALUE_LIST);
1229    gconf_value_set_list_type(value_with_list, list_type);
1230    gconf_value_set_list_nocopy(value_with_list, value_list);
1231
1232    return value_with_list;
1233  }
1234}
1235
1236
1237static GConfValue*
1238from_primitive(GConfValueType type, gconstpointer address)
1239{
1240  GConfValue* val;
1241
1242  val = gconf_value_new(type);
1243
1244  switch (type)
1245    {
1246    case GCONF_VALUE_INT:
1247      gconf_value_set_int(val, *((const gint*)address));
1248      break;
1249
1250    case GCONF_VALUE_BOOL:
1251      gconf_value_set_bool(val, *((const gboolean*)address));
1252      break;
1253
1254    case GCONF_VALUE_STRING:
1255      gconf_value_set_string(val, *((const gchar**)address));
1256      break;
1257
1258    case GCONF_VALUE_FLOAT:
1259      gconf_value_set_float(val, *((const gdouble*)address));
1260      break;
1261
1262    case GCONF_VALUE_SCHEMA:
1263      gconf_value_set_schema(val, *((GConfSchema**)address));
1264      break;
1265     
1266    default:
1267      g_assert_not_reached();
1268      break;
1269    }
1270
1271  return val;
1272}
1273
1274GConfValue*
1275gconf_value_pair_from_primitive_pair(GConfValueType car_type,
1276                                     GConfValueType cdr_type,
1277                                     gconstpointer address_of_car,
1278                                     gconstpointer address_of_cdr)
1279{
1280  GConfValue* pair;
1281  GConfValue* car;
1282  GConfValue* cdr;
1283 
1284  g_return_val_if_fail(car_type != GCONF_VALUE_INVALID, NULL);
1285  g_return_val_if_fail(car_type != GCONF_VALUE_LIST, NULL);
1286  g_return_val_if_fail(car_type != GCONF_VALUE_PAIR, NULL);
1287  g_return_val_if_fail(cdr_type != GCONF_VALUE_INVALID, NULL);
1288  g_return_val_if_fail(cdr_type != GCONF_VALUE_LIST, NULL);
1289  g_return_val_if_fail(cdr_type != GCONF_VALUE_PAIR, NULL);
1290  g_return_val_if_fail(address_of_car != NULL, NULL);
1291  g_return_val_if_fail(address_of_cdr != NULL, NULL);
1292 
1293  car = from_primitive(car_type, address_of_car);
1294  cdr = from_primitive(cdr_type, address_of_cdr);
1295
1296  pair = gconf_value_new(GCONF_VALUE_PAIR);
1297  gconf_value_set_car_nocopy(pair, car);
1298  gconf_value_set_cdr_nocopy(pair, cdr);
1299
1300  return pair;
1301}
1302
1303
1304GSList*
1305gconf_value_list_to_primitive_list_destructive(GConfValue* val,
1306                                               GConfValueType list_type,
1307                                               GError** err)
1308{
1309  GSList* retval;
1310
1311  g_return_val_if_fail(val != NULL, NULL);
1312  g_return_val_if_fail(list_type != GCONF_VALUE_INVALID, NULL);
1313  g_return_val_if_fail(list_type != GCONF_VALUE_LIST, NULL);
1314  g_return_val_if_fail(list_type != GCONF_VALUE_PAIR, NULL);
1315  g_return_val_if_fail(err == NULL || *err == NULL, NULL);
1316 
1317  if (val->type != GCONF_VALUE_LIST)
1318    {
1319      if (err)
1320        *err = gconf_error_new(GCONF_ERROR_TYPE_MISMATCH,
1321                               _("Expected list, got %s"),
1322                               gconf_value_type_to_string(val->type));
1323      gconf_value_free(val);
1324      return NULL;
1325    }
1326
1327  if (gconf_value_get_list_type(val) != list_type)
1328    {
1329      if (err)
1330        *err = gconf_error_new(GCONF_ERROR_TYPE_MISMATCH,
1331                               _("Expected list of %s, got list of %s"),
1332                               gconf_value_type_to_string(list_type),
1333                               gconf_value_type_to_string(val->type));
1334      gconf_value_free(val);
1335      return NULL;
1336    }
1337
1338  g_assert(gconf_value_get_list_type(val) == list_type);
1339     
1340  retval = gconf_value_get_list(val);
1341
1342  /* Cheating the API to avoid a list copy; set this to NULL to
1343         avoid destroying the list */
1344  val->d.list_data.list = NULL;
1345     
1346  gconf_value_free(val);
1347  val = NULL;
1348     
1349  {
1350    /* map (typeChange, retval) */
1351    GSList* tmp;
1352
1353    tmp = retval;
1354
1355    while (tmp != NULL)
1356      {
1357        GConfValue* elem = tmp->data;
1358
1359        g_assert(elem != NULL);
1360        g_assert(elem->type == list_type);
1361           
1362        switch (list_type)
1363          {
1364          case GCONF_VALUE_INT:
1365          case GCONF_VALUE_BOOL:
1366            tmp->data = GINT_TO_POINTER(gconf_value_get_int(elem));
1367            break;
1368               
1369          case GCONF_VALUE_FLOAT:
1370            {
1371              gdouble* d = g_new(gdouble, 1);
1372              *d = gconf_value_get_float(elem);
1373              tmp->data = d;
1374            }
1375            break;
1376
1377          case GCONF_VALUE_STRING:
1378            {
1379              /* Cheat again, and steal the string from the value */
1380              tmp->data = elem->d.string_data;
1381              elem->d.string_data = NULL;
1382            }
1383            break;
1384
1385          case GCONF_VALUE_SCHEMA:
1386            {
1387              /* and also steal the schema... */
1388              tmp->data = elem->d.schema_data;
1389              elem->d.schema_data = NULL;
1390            }
1391            break;
1392               
1393          default:
1394            g_assert_not_reached();
1395            break;
1396          }
1397
1398        /* Clean up the value */
1399        gconf_value_free(elem);
1400           
1401        tmp = g_slist_next(tmp);
1402      }
1403  } /* list conversion block */
1404     
1405  return retval;
1406}
1407
1408
1409static void
1410primitive_value(gpointer retloc, GConfValue* val)
1411{
1412  switch (val->type)
1413    {
1414    case GCONF_VALUE_INT:
1415      *((gint*)retloc) = gconf_value_get_int(val);
1416      break;
1417
1418    case GCONF_VALUE_FLOAT:
1419      *((gdouble*)retloc) = gconf_value_get_float(val);
1420      break;
1421
1422    case GCONF_VALUE_STRING:
1423      {
1424        *((gchar**)retloc) = val->d.string_data;
1425        /* cheat and steal the string to avoid a copy */
1426        val->d.string_data = NULL;
1427      }
1428      break;
1429
1430    case GCONF_VALUE_BOOL:
1431      *((gboolean*)retloc) = gconf_value_get_bool(val);
1432      break;
1433
1434    case GCONF_VALUE_SCHEMA:
1435      *((GConfSchema**)retloc) = gconf_value_get_schema(val);
1436      break;
1437     
1438    default:
1439      g_assert_not_reached();
1440      break;
1441    }
1442}
1443
1444gboolean
1445gconf_value_pair_to_primitive_pair_destructive(GConfValue* val,
1446                                               GConfValueType car_type,
1447                                               GConfValueType cdr_type,
1448                                               gpointer car_retloc,
1449                                               gpointer cdr_retloc,
1450                                               GError** err)
1451{
1452  GConfValue* car;
1453  GConfValue* cdr;
1454
1455  g_return_val_if_fail(val != NULL, FALSE);
1456  g_return_val_if_fail(car_type != GCONF_VALUE_INVALID, FALSE);
1457  g_return_val_if_fail(car_type != GCONF_VALUE_LIST, FALSE);
1458  g_return_val_if_fail(car_type != GCONF_VALUE_PAIR, FALSE);
1459  g_return_val_if_fail(cdr_type != GCONF_VALUE_INVALID, FALSE);
1460  g_return_val_if_fail(cdr_type != GCONF_VALUE_LIST, FALSE);
1461  g_return_val_if_fail(cdr_type != GCONF_VALUE_PAIR, FALSE);
1462  g_return_val_if_fail(car_retloc != NULL, FALSE);
1463  g_return_val_if_fail(cdr_retloc != NULL, FALSE);
1464  g_return_val_if_fail(err == NULL || *err == NULL, FALSE); 
1465     
1466  if (val->type != GCONF_VALUE_PAIR)
1467    {
1468      if (err)
1469        *err = gconf_error_new(GCONF_ERROR_TYPE_MISMATCH,
1470                               _("Expected pair, got %s"),
1471                               gconf_value_type_to_string(val->type));
1472      gconf_value_free(val);
1473      return FALSE;
1474    }
1475
1476  car = gconf_value_get_car(val);
1477  cdr = gconf_value_get_cdr(val);
1478     
1479  if (car == NULL ||
1480      cdr == NULL)
1481    {
1482      if (err)
1483        *err = gconf_error_new(GCONF_ERROR_TYPE_MISMATCH,
1484                               _("Expected (%s,%s) pair, got a pair with one or both values missing"),
1485                               gconf_value_type_to_string(car_type),
1486                               gconf_value_type_to_string(cdr_type));
1487
1488      gconf_value_free(val);
1489      return FALSE;
1490    }
1491
1492  g_assert(car != NULL);
1493  g_assert(cdr != NULL);
1494     
1495  if (car->type != car_type ||
1496      cdr->type != cdr_type)
1497    {
1498      if (err)
1499        *err = gconf_error_new(GCONF_ERROR_TYPE_MISMATCH,
1500                               _("Expected pair of type (%s,%s) got type (%s,%s)"),
1501                               gconf_value_type_to_string(car_type),
1502                               gconf_value_type_to_string(cdr_type),
1503                               gconf_value_type_to_string(car->type),
1504                               gconf_value_type_to_string(cdr->type));
1505      gconf_value_free(val);
1506      return FALSE;
1507    }
1508
1509  primitive_value(car_retloc, car);
1510  primitive_value(cdr_retloc, cdr);
1511
1512  gconf_value_free(val);
1513
1514  return TRUE;
1515}
1516
1517
1518
1519/*
1520 * Encode/decode
1521 */
1522
1523gchar*
1524gconf_quote_string   (const gchar* src)
1525{
1526  gchar* dest;
1527  const gchar* s;
1528  gchar* d;
1529
1530  g_return_val_if_fail(src != NULL, NULL);
1531 
1532  /* waste memory! woo-hoo! */
1533  dest = g_malloc0(strlen(src)*2+4);
1534 
1535  d = dest;
1536
1537  *d = '"';
1538  ++d;
1539 
1540  s = src;
1541  while (*s)
1542    {
1543      switch (*s)
1544        {
1545        case '"':
1546          {
1547            *d = '\\';
1548            ++d;
1549            *d = '"';
1550            ++d;
1551          }
1552          break;
1553         
1554        case '\\':
1555          {
1556            *d = '\\';
1557            ++d;
1558            *d = '\\';
1559            ++d;
1560          }
1561          break;
1562         
1563        default:
1564          {
1565            *d = *s;
1566            ++d;
1567          }
1568          break;
1569        }
1570      ++s;
1571    }
1572
1573  /* End with quote mark and NULL */
1574  *d = '"';
1575  ++d;
1576  *d = '\0';
1577 
1578  return dest;
1579}
1580
1581gchar*
1582gconf_unquote_string (const gchar* str, const gchar** end, GError** err)
1583{
1584  gchar* unq;
1585  gchar* unq_end = NULL;
1586
1587  g_return_val_if_fail(end != NULL, NULL);
1588  g_return_val_if_fail(err == NULL || *err == NULL, NULL);
1589  g_return_val_if_fail(str != NULL, NULL);
1590 
1591  unq = g_strdup(str);
1592
1593  gconf_unquote_string_inplace(unq, &unq_end, err);
1594
1595  *end = (str + (unq_end - unq));
1596
1597  return unq;
1598}
1599
1600void
1601gconf_unquote_string_inplace (gchar* str, gchar** end, GError** err)
1602{
1603  gchar* dest;
1604  gchar* s;
1605
1606  g_return_if_fail(end != NULL);
1607  g_return_if_fail(err == NULL || *err == NULL);
1608  g_return_if_fail(str != NULL);
1609 
1610  dest = s = str;
1611
1612  if (*s != '"')
1613    {
1614      if (err)
1615        *err = gconf_error_new(GCONF_ERROR_PARSE_ERROR,
1616                               _("Quoted string doesn't begin with a quotation mark"));
1617      *end = str;
1618      return;
1619    }
1620
1621  /* Skip the initial quote mark */
1622  ++s;
1623 
1624  while (*s)
1625    {
1626      g_assert(s > dest); /* loop invariant */
1627     
1628      switch (*s)
1629        {
1630        case '"':
1631          /* End of the string, return now */
1632          *dest = '\0';
1633          ++s;
1634          *end = s;
1635          return;
1636          break;
1637
1638        case '\\':
1639          /* Possible escaped quote or \ */
1640          ++s;
1641          if (*s == '"')
1642            {
1643              *dest = *s;
1644              ++s;
1645              ++dest;
1646            }
1647          else if (*s == '\\')
1648            {
1649              *dest = *s;
1650              ++s;
1651              ++dest;
1652            }
1653          else
1654            {
1655              /* not an escaped char */
1656              *dest = '\\';
1657              ++dest;
1658              /* ++s already done. */
1659            }
1660          break;
1661
1662        default:
1663          *dest = *s;
1664          ++dest;
1665          ++s;
1666          break;
1667        }
1668
1669      g_assert(s > dest); /* loop invariant */
1670    }
1671 
1672  /* If we reach here this means the close quote was never encountered */
1673
1674  *dest = '\0';
1675 
1676  if (err)
1677    *err = gconf_error_new(GCONF_ERROR_PARSE_ERROR,
1678                           _("Quoted string doesn't end with a quotation mark"));
1679  *end = s;
1680  return;
1681}
1682
1683/* The encoding format
1684
1685   The first byte of the encoded string is the type of the value:
1686
1687    i  int
1688    b  bool
1689    f  float
1690    s  string
1691    c  schema
1692    p  pair
1693    l  list
1694    v  invalid
1695
1696    For int, the rest of the encoded value is the integer to be parsed with atoi()
1697    For bool, the rest is 't' or 'f'
1698    For float, the rest is a float to parse with g_strtod()
1699    For string, the rest is the string (not quoted)
1700    For schema, the encoding is complicated; see below.
1701    For pair, the rest is two primitive encodings (ibcfs), quoted, separated by a comma,
1702              car before cdr
1703    For list, first character is type, the rest is primitive encodings, quoted,
1704              separated by commas
1705
1706    Schema:
1707
1708    After the 'c' indicating schema, the second character is a byte indicating
1709    the type the schema expects. Then a comma, and the quoted locale, or "" for none.
1710    comma, and quoted short description; comma, quoted long description; comma, default
1711    value in the encoded format given above, quoted.
1712*/
1713
1714static gchar type_byte(GConfValueType type)
1715{
1716  switch (type)
1717    {
1718    case GCONF_VALUE_INT:
1719      return 'i';
1720      break;
1721       
1722    case GCONF_VALUE_BOOL:
1723      return 'b';
1724      break;
1725
1726    case GCONF_VALUE_FLOAT:
1727      return 'f';
1728      break;
1729
1730    case GCONF_VALUE_STRING:
1731      return 's';
1732      break;
1733
1734    case GCONF_VALUE_SCHEMA:
1735      return 'c';
1736      break;
1737
1738    case GCONF_VALUE_LIST:
1739      return 'l';
1740      break;
1741
1742    case GCONF_VALUE_PAIR:
1743      return 'p';
1744      break;
1745
1746    case GCONF_VALUE_INVALID:
1747      return 'v';
1748      break;
1749     
1750    default:
1751      g_assert_not_reached();
1752      return '\0';
1753      break;
1754    }
1755}
1756
1757GConfValueType
1758byte_type(gchar byte)
1759{
1760  switch (byte)
1761    {
1762    case 'i':
1763      return GCONF_VALUE_INT;
1764      break;
1765
1766    case 'b':
1767      return GCONF_VALUE_BOOL;
1768      break;
1769
1770    case 's':
1771      return GCONF_VALUE_STRING;
1772      break;
1773
1774    case 'c':
1775      return GCONF_VALUE_SCHEMA;
1776      break;
1777
1778    case 'f':
1779      return GCONF_VALUE_FLOAT;
1780      break;
1781
1782    case 'l':
1783      return GCONF_VALUE_LIST;
1784      break;
1785
1786    case 'p':
1787      return GCONF_VALUE_PAIR;
1788      break;
1789     
1790    case 'v':
1791      return GCONF_VALUE_INVALID;
1792      break;
1793
1794    default:
1795      return GCONF_VALUE_INVALID;
1796      break;
1797    }
1798}
1799
1800GConfValue*
1801gconf_value_decode (const gchar* encoded)
1802{
1803  GConfValueType type;
1804  GConfValue* val;
1805  const gchar* s;
1806 
1807  type = byte_type(*encoded);
1808
1809  if (type == GCONF_VALUE_INVALID)
1810    return NULL;
1811
1812  val = gconf_value_new(type);
1813
1814  s = encoded + 1;
1815 
1816  switch (val->type)
1817    {
1818    case GCONF_VALUE_INT:
1819      gconf_value_set_int(val, atoi(s));
1820      break;
1821       
1822    case GCONF_VALUE_BOOL:
1823      gconf_value_set_bool(val, *s == 't' ? TRUE : FALSE);
1824      break;
1825
1826    case GCONF_VALUE_FLOAT:
1827      {
1828        double d;
1829        gchar* endptr = NULL;
1830       
1831        d = g_strtod(s, &endptr);
1832        if (endptr == s)
1833          g_warning("Failure converting string to double in %s", G_GNUC_FUNCTION);
1834        gconf_value_set_float(val, d);
1835      }
1836      break;
1837
1838    case GCONF_VALUE_STRING:
1839      {
1840        gconf_value_set_string(val, s);
1841      }
1842      break;
1843
1844    case GCONF_VALUE_SCHEMA:
1845      {
1846        GConfSchema* sc = gconf_schema_new();
1847        const gchar* end = NULL;
1848        gchar* unquoted;
1849       
1850        gconf_value_set_schema(val, sc);
1851
1852        gconf_schema_set_type(sc, byte_type(*s));
1853        ++s;
1854        gconf_schema_set_list_type(sc, byte_type(*s));
1855        ++s;
1856        gconf_schema_set_car_type(sc, byte_type(*s));
1857        ++s;
1858        gconf_schema_set_cdr_type(sc, byte_type(*s));
1859        ++s;
1860
1861        /* locale */
1862        unquoted = gconf_unquote_string(s, &end, NULL);
1863
1864        gconf_schema_set_locale(sc, unquoted);
1865
1866        g_free(unquoted);
1867       
1868        if (*end != ',')
1869          g_warning("no comma after locale in schema");
1870
1871        ++end;
1872        s = end;
1873
1874        /* short */
1875        unquoted = gconf_unquote_string(s, &end, NULL);
1876
1877        gconf_schema_set_short_desc(sc, unquoted);
1878
1879        g_free(unquoted);
1880       
1881        if (*end != ',')
1882          g_warning("no comma after short desc in schema");
1883
1884        ++end;
1885        s = end;
1886
1887
1888        /* long */
1889        unquoted = gconf_unquote_string(s, &end, NULL);
1890
1891        gconf_schema_set_long_desc(sc, unquoted);
1892
1893        g_free(unquoted);
1894       
1895        if (*end != ',')
1896          g_warning("no comma after long desc in schema");
1897
1898        ++end;
1899        s = end;
1900       
1901       
1902        /* default value */
1903        unquoted = gconf_unquote_string(s, &end, NULL);
1904
1905        gconf_schema_set_default_value_nocopy(sc, gconf_value_decode(unquoted));
1906
1907        g_free(unquoted);
1908       
1909        if (*end != '\0')
1910          g_warning("trailing junk after encoded schema");
1911      }
1912      break;
1913
1914    case GCONF_VALUE_LIST:
1915      {
1916        GSList* value_list = NULL;
1917
1918        gconf_value_set_list_type(val, byte_type(*s));
1919        ++s;
1920
1921        while (*s)
1922          {
1923            gchar* unquoted;
1924            const gchar* end;
1925           
1926            GConfValue* elem;
1927           
1928            unquoted = gconf_unquote_string(s, &end, NULL);           
1929
1930            elem = gconf_value_decode(unquoted);
1931
1932            g_free(unquoted);
1933           
1934            if (elem)
1935              value_list = g_slist_prepend(value_list, elem);
1936           
1937            s = end;
1938            if (*s == ',')
1939              ++s;
1940            else if (*s != '\0')
1941              {
1942                g_warning("weird character in encoded list");
1943                break; /* error */
1944              }
1945          }
1946
1947        value_list = g_slist_reverse(value_list);
1948
1949        gconf_value_set_list_nocopy(val, value_list);
1950      }
1951      break;
1952
1953    case GCONF_VALUE_PAIR:
1954      {
1955        gchar* unquoted;
1956        const gchar* end;
1957       
1958        GConfValue* car;
1959        GConfValue* cdr;
1960       
1961        unquoted = gconf_unquote_string(s, &end, NULL);           
1962       
1963        car = gconf_value_decode(unquoted);
1964
1965        g_free(unquoted);
1966       
1967        s = end;
1968        if (*s == ',')
1969          ++s;
1970        else
1971          {
1972            g_warning("weird character in encoded pair");
1973          }
1974       
1975        unquoted = gconf_unquote_string(s, &end, NULL);
1976       
1977        cdr = gconf_value_decode(unquoted);
1978        g_free(unquoted);
1979
1980
1981        gconf_value_set_car_nocopy(val, car);
1982        gconf_value_set_cdr_nocopy(val, cdr);
1983      }
1984      break;
1985
1986    default:
1987      g_assert_not_reached();
1988      break;
1989    }
1990
1991  return val;
1992}
1993
1994gchar*
1995gconf_value_encode (GConfValue* val)
1996{
1997  gchar* retval = NULL;
1998 
1999  g_return_val_if_fail(val != NULL, NULL);
2000
2001  switch (val->type)
2002    {
2003    case GCONF_VALUE_INT:
2004      retval = g_strdup_printf("i%d", gconf_value_get_int(val));
2005      break;
2006       
2007    case GCONF_VALUE_BOOL:
2008      retval = g_strdup_printf("b%c", gconf_value_get_bool(val) ? 't' : 'f');
2009      break;
2010
2011    case GCONF_VALUE_FLOAT:
2012      retval = g_strdup_printf("f%g", gconf_value_get_float(val));
2013      break;
2014
2015    case GCONF_VALUE_STRING:
2016      retval = g_strdup_printf("s%s", gconf_value_get_string(val));
2017      break;
2018
2019    case GCONF_VALUE_SCHEMA:
2020      {
2021        gchar* tmp;
2022        gchar* retval;
2023        gchar* quoted;
2024        gchar* encoded;
2025        GConfSchema* sc;
2026
2027        sc = gconf_value_get_schema(val);
2028       
2029        tmp = g_strdup_printf("c%c%c%c%c,",
2030                              type_byte(gconf_schema_get_type(sc)),
2031                              type_byte(gconf_schema_get_list_type(sc)),
2032                              type_byte(gconf_schema_get_car_type(sc)),
2033                              type_byte(gconf_schema_get_cdr_type(sc)));
2034
2035        quoted = gconf_quote_string(gconf_schema_get_locale(sc) ?
2036                                    gconf_schema_get_locale(sc) : "");
2037        retval = g_strconcat(tmp, quoted, ",", NULL);
2038
2039        g_free(tmp);
2040        g_free(quoted);
2041
2042        tmp = retval;
2043        quoted = gconf_quote_string(gconf_schema_get_short_desc(sc) ?
2044                                    gconf_schema_get_short_desc(sc) : "");
2045
2046        retval = g_strconcat(tmp, quoted, ",", NULL);
2047
2048        g_free(tmp);
2049        g_free(quoted);
2050
2051
2052        tmp = retval;
2053        quoted = gconf_quote_string(gconf_schema_get_long_desc(sc) ?
2054                                    gconf_schema_get_long_desc(sc) : "");
2055
2056        retval = g_strconcat(tmp, quoted, ",", NULL);
2057
2058        g_free(tmp);
2059        g_free(quoted);
2060       
2061
2062        if (gconf_schema_get_default_value(sc) != NULL)
2063          encoded = gconf_value_encode(gconf_schema_get_default_value(sc));
2064        else
2065          encoded = g_strdup("");
2066
2067        tmp = retval;
2068         
2069        quoted = gconf_quote_string(encoded);
2070
2071        retval = g_strconcat(tmp, quoted, NULL);
2072
2073        g_free(tmp);
2074        g_free(quoted);
2075        g_free(encoded);
2076      }
2077      break;
2078
2079    case GCONF_VALUE_LIST:
2080      {
2081        GSList* tmp;
2082
2083        retval = g_strdup_printf("l%c", type_byte(gconf_value_get_list_type(val)));
2084       
2085        tmp = gconf_value_get_list(val);
2086
2087        while (tmp != NULL)
2088          {
2089            GConfValue* elem = tmp->data;
2090            gchar* encoded;
2091            gchar* quoted;
2092           
2093            g_assert(elem != NULL);
2094
2095            encoded = gconf_value_encode(elem);
2096
2097            quoted = gconf_quote_string(encoded);
2098
2099            g_free(encoded);
2100
2101            {
2102              gchar* free_me;
2103              free_me = retval;
2104             
2105              retval = g_strconcat(retval, ",", quoted, NULL);
2106             
2107              g_free(quoted);
2108              g_free(free_me);
2109            }
2110           
2111            tmp = g_slist_next(tmp);
2112          }
2113      }
2114      break;
2115
2116    case GCONF_VALUE_PAIR:
2117      {
2118        gchar* car_encoded;
2119        gchar* cdr_encoded;
2120        gchar* car_quoted;
2121        gchar* cdr_quoted;
2122
2123        car_encoded = gconf_value_encode(gconf_value_get_car(val));
2124        cdr_encoded = gconf_value_encode(gconf_value_get_cdr(val));
2125
2126        car_quoted = gconf_quote_string(car_encoded);
2127        cdr_quoted = gconf_quote_string(cdr_encoded);
2128
2129        retval = g_strconcat("p", car_quoted, ",", cdr_quoted, NULL);
2130
2131        g_free(car_encoded);
2132        g_free(cdr_encoded);
2133        g_free(car_quoted);
2134        g_free(cdr_quoted);
2135      }
2136      break;
2137
2138    default:
2139      g_assert_not_reached();
2140      break;
2141     
2142    }
2143
2144  return retval;
2145}
2146
2147gboolean
2148gconf_handle_oaf_exception(CORBA_Environment* ev, GError** err)
2149{
2150  switch (ev->_major)
2151    {
2152    case CORBA_NO_EXCEPTION:
2153      CORBA_exception_free(ev);
2154      return FALSE;
2155      break;
2156    case CORBA_SYSTEM_EXCEPTION:
2157      if (err)
2158        *err = gconf_error_new(GCONF_ERROR_NO_SERVER, _("CORBA error: %s"),
2159                               CORBA_exception_id(ev));
2160      CORBA_exception_free(ev);
2161      return TRUE;
2162      break;
2163
2164    case CORBA_USER_EXCEPTION:
2165      {
2166        const gchar* id = CORBA_exception_id(ev);
2167
2168        if (strcmp(id, "IDL:OAF/GeneralError:1.0") == 0)
2169          {
2170            OAF_GeneralError* ge = CORBA_exception_value(ev);
2171
2172            if (err)
2173              *err = gconf_error_new(GCONF_ERROR_OAF_ERROR,
2174                                     _("OAF problem description: '%s'"),
2175                                     ge->description);
2176          }
2177        else if (strcmp(id,"IDL:OAF/ActivationContext/NotListed:1.0" ) == 0)
2178          {
2179            if (err)
2180              *err = gconf_error_new(GCONF_ERROR_OAF_ERROR, _("attempt to remove not-listed OAF object directory"));
2181          }
2182        else if (strcmp(id,"IDL:OAF/ActivationContext/AlreadyListed:1.0" ) == 0)
2183          {
2184            if (err)
2185              *err = gconf_error_new(GCONF_ERROR_OAF_ERROR, _("attempt to add already-listed OAF directory"));
2186          }
2187        else if (strcmp(id,"IDL:OAF/ActivationContext/ParseFailed:1.0") == 0)
2188          {
2189            OAF_ActivationContext_ParseFailed* pe = CORBA_exception_value(ev);
2190           
2191            if (err)
2192              *err = gconf_error_new(GCONF_ERROR_OAF_ERROR, _("OAF parse error: %s"), pe->description);
2193          }
2194        else
2195          {
2196            if (err)
2197              *err = gconf_error_new(GCONF_ERROR_OAF_ERROR, _("Unknown OAF error"));
2198          }
2199       
2200        CORBA_exception_free(ev);
2201        return TRUE;
2202      }
2203      break;
2204    default:
2205      g_assert_not_reached();
2206      return TRUE;
2207      break;
2208    }
2209}
2210
2211/* Sleep */
2212
2213#ifdef HAVE_NANOSLEEP
2214
2215void
2216gconf_nanosleep(gulong useconds)
2217{
2218  struct timespec ts;
2219
2220  ts.tv_sec = (long int)(useconds/1000000);
2221  ts.tv_nsec = (long int)(useconds%1000000)*1000ul;
2222 
2223  nanosleep(&ts,NULL);
2224}
2225
2226#elif HAVE_USLEEP
2227
2228void
2229gconf_nanosleep(gulong useconds)
2230{
2231  usleep(useconds);
2232}
2233
2234#else
2235#error "need nanosleep or usleep right now (fix with simple select() hack)"
2236#endif
2237
2238/*
2239 * Locks using directories, to work on NFS (at least potentially)
2240 */
2241
2242struct _GConfLock {
2243  gchar* lock_directory;
2244};
2245
2246static void
2247gconf_lock_destroy(GConfLock* lock)
2248{
2249  g_free(lock->lock_directory);
2250  g_free(lock);
2251}
2252
2253GConfLock*
2254gconf_get_lock(const gchar* lock_directory,
2255               GError** err)
2256{
2257  GConfLock* lock;
2258  gboolean got_it = FALSE;
2259  gboolean error_occurred = FALSE;
2260  gboolean stale = FALSE;
2261  gchar* iorfile;
2262 
2263  g_return_val_if_fail(lock_directory != NULL, NULL);
2264 
2265  lock = g_new(GConfLock, 1);
2266
2267  lock->lock_directory = g_strdup(lock_directory);
2268
2269  iorfile = g_strconcat(lock->lock_directory, "/ior", NULL);
2270 
2271  if (mkdir(lock->lock_directory, 0700) < 0)
2272    {
2273      if (errno == EEXIST)
2274        {
2275          /* Check the current IOR file and ping its daemon */
2276          FILE* fp;
2277         
2278          fp = fopen(iorfile, "r");
2279         
2280          if (fp == NULL)
2281            {
2282              gconf_log(GCL_WARNING, _("No ior file in `%s'"),
2283                        lock->lock_directory);
2284              stale = TRUE;
2285              got_it = TRUE;
2286              goto out;
2287            }
2288          else
2289            {
2290              gchar buf[2048] = { '\0' };
2291              gchar* str = NULL;
2292              fgets(buf, 2047, fp);
2293              fclose(fp);
2294
2295              /* The lockfile format is <pid>:<ior> for gconfd
2296                 or <pid>:none for gconftool */
2297              str = buf;
2298              while (isdigit(*str))
2299                ++str;
2300
2301              if (*str == ':')
2302                ++str;
2303             
2304              if (str[0] == 'n' &&
2305                  str[1] == 'o' &&
2306                  str[2] == 'n' &&
2307                  str[3] == 'e')
2308                {
2309                  /* It's locked by gconftool, not a daemon;
2310                     the daemon always "wins" the lock, with a warning */
2311                  if (gconf_in_daemon_mode())
2312                    {
2313                      gconf_log(GCL_WARNING, _("gconfd taking lock `%s' from some other process"),
2314                                lock->lock_directory);
2315                      stale = TRUE;
2316                      got_it = TRUE;
2317                      goto out;
2318                    }
2319                  else
2320                    {
2321                      error_occurred = TRUE;
2322                      gconf_set_error(err,
2323                                      GCONF_ERROR_LOCK_FAILED,
2324                                      _("Another program has lock `%s'"),
2325                                      lock->lock_directory);
2326                      goto out;
2327                    }
2328                }
2329              else
2330                {
2331                  ConfigServer server;
2332                  CORBA_ORB orb;
2333                  CORBA_Environment ev;
2334
2335                  CORBA_exception_init(&ev);
2336                 
2337                  orb = oaf_orb_get();
2338
2339                  if (orb == NULL)
2340                    {
2341                      error_occurred = TRUE;
2342                      gconf_set_error(err,
2343                                      GCONF_ERROR_LOCK_FAILED,
2344                                      _("couldn't contact ORB to ping existing gconfd"));
2345                      goto out;
2346                    }
2347                 
2348                  server = CORBA_ORB_string_to_object(orb, str, &ev);
2349
2350                  if (CORBA_Object_is_nil(server, &ev))
2351                    {
2352                      gconf_log(GCL_WARNING, _("Removing stale lock `%s' because IOR couldn't be converted to object reference, IOR `%s'"),
2353                                lock->lock_directory, str);
2354                      stale = TRUE;
2355                      got_it = TRUE;
2356                      goto out;
2357                    }
2358                  else
2359                    {
2360                      ConfigServer_ping(server, &ev);
2361     
2362                      if (ev._major != CORBA_NO_EXCEPTION)
2363                        {
2364                          gconf_log(GCL_WARNING, _("Removing stale lock `%s' because of error pinging server: %s"),
2365                                    lock->lock_directory, CORBA_exception_id(&ev));
2366                          CORBA_exception_free(&ev);
2367                          stale = TRUE;
2368                          got_it = TRUE;
2369                          goto out;
2370                        }
2371                      else
2372                        {
2373                          error_occurred = TRUE;
2374                          gconf_set_error(err,
2375                                          GCONF_ERROR_LOCK_FAILED,
2376                                          _("GConf configuration daemon (gconfd) has lock `%s'"),
2377                                          lock->lock_directory);
2378                          goto out;
2379                        }
2380                    }
2381                }
2382            }
2383        }
2384      else
2385        {
2386          /* give up */
2387          error_occurred = TRUE;
2388          gconf_set_error(err,
2389                          GCONF_ERROR_LOCK_FAILED,
2390                          _("couldn't create directory `%s': %s"),
2391                          lock->lock_directory, strerror(errno));
2392          goto out;
2393        }
2394    }
2395  else
2396    {
2397      got_it = TRUE;
2398    }
2399 
2400 out:
2401
2402  if (error_occurred)
2403    {
2404      g_assert(!got_it);
2405
2406      g_free(iorfile);
2407      gconf_lock_destroy(lock);
2408      return NULL;
2409    }
2410
2411  g_assert(got_it);
2412 
2413  if (stale)
2414    unlink(iorfile);
2415
2416  {
2417    int fd = -1;
2418
2419    fd = open(iorfile, O_WRONLY | O_CREAT | O_TRUNC, 0700);
2420
2421    if (fd < 0)
2422      {
2423        gconf_set_error(err,
2424                        GCONF_ERROR_LOCK_FAILED,
2425                        _("Can't create lock `%s': %s"),
2426                        iorfile, strerror(errno));
2427        g_free(iorfile);
2428        gconf_lock_destroy(lock);
2429        return NULL;
2430      }
2431    else
2432      {
2433        const gchar* ior;
2434        int retval;
2435        gchar* s;
2436       
2437        s = g_strdup_printf("%u:", (guint)getpid());
2438       
2439        retval = write(fd, s, strlen(s));
2440
2441        g_free(s);
2442       
2443        if (retval >= 0)
2444          {
2445            ior = gconf_get_daemon_ior();
2446           
2447            if (ior == NULL)
2448              {
2449                retval = write(fd, "none", 4);
2450              }
2451            else
2452              {
2453                retval = write(fd, ior, strlen(ior));
2454              }
2455          }
2456
2457        if (retval < 0)
2458          {
2459            gconf_set_error(err,
2460                            GCONF_ERROR_LOCK_FAILED,
2461                            _("Can't write to file `%s': %s"),
2462                            iorfile, strerror(errno));
2463            close(fd);
2464            g_free(iorfile);
2465            gconf_lock_destroy(lock);           
2466            return NULL;
2467          }
2468
2469        if (close(fd) < 0)
2470          {
2471            gconf_set_error(err,
2472                            GCONF_ERROR_LOCK_FAILED,
2473                            _("Failed to close file `%s': %s"),
2474                            iorfile, strerror(errno));
2475            g_free(iorfile);
2476            gconf_lock_destroy(lock);           
2477            return NULL;
2478          }
2479      }
2480  }
2481 
2482  g_free(iorfile);
2483  return lock;
2484}
2485
2486gboolean
2487gconf_release_lock(GConfLock* lock,
2488                   GError** err)
2489{
2490  gchar* iorfile;
2491  FILE* fp;
2492  gchar buf[256] = { '\0' };
2493  gchar* str = NULL;
2494  gulong pid;
2495 
2496  iorfile = g_strconcat(lock->lock_directory, "/ior", NULL);
2497         
2498  fp = fopen(iorfile, "r");
2499 
2500  if (fp == NULL)
2501    {
2502      gconf_set_error(err,
2503                      GCONF_ERROR_FAILED,
2504                      _("Can't open lock file `%s'; assuming it isn't ours: %s"),
2505                      iorfile, strerror(errno));
2506      g_free(iorfile);
2507      return FALSE;
2508    }
2509
2510  fgets(buf, 255, fp);
2511  fclose(fp);
2512
2513  /* The lockfile format is <pid>:<ior> for gconfd
2514     or <pid>:none for gconftool */
2515
2516  /* get PID to see if it's ours */
2517  pid = strtoul(buf, &str, 10);
2518
2519  if (buf == str)
2520    {
2521      gconf_log(GCL_WARNING, _("Corrupt lock file `%s', removing anyway"),
2522                iorfile);
2523
2524    }
2525  else
2526    {
2527      if (pid != getpid())
2528        {
2529          gconf_set_error(err,
2530                          GCONF_ERROR_FAILED,
2531                          _("Didn't create lock file `%s' (creator pid %u, our pid %u; assuming someone took our lock"),
2532                          iorfile, (guint)pid, (guint)getpid());
2533          g_free(iorfile);
2534          return FALSE;
2535        }
2536    }
2537 
2538  /* Race condition here, someone could replace the lockfile
2539     before we decide whether it's ours; oh well */
2540  unlink(iorfile);
2541
2542  g_free(iorfile);
2543 
2544  if (rmdir(lock->lock_directory) < 0)
2545    {
2546      gconf_set_error(err,
2547                      GCONF_ERROR_FAILED,
2548                      _("Failed to release lock directory `%s': %s"),
2549                      lock->lock_directory,
2550                      strerror(errno));
2551      gconf_lock_destroy(lock);
2552      return FALSE;
2553    }
2554  gconf_lock_destroy(lock);
2555  return TRUE;
2556}
2557
2558
Note: See TracBrowser for help on using the repository browser.