1
/* Config reader routines
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.
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.
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.
26
#include <sys/types.h>
34
#include "ve-config.h"
36
typedef struct _VeSection VeSection;
37
typedef struct _VeLine VeLine;
40
VE_LINE_TEXT /* comment or some other line */,
47
char *fullkey; /* key with section name */
48
const char *key; /* key without section name, pointer
49
into fullkey, or NULL if of type TEXT */
74
static GHashTable *config_hash = NULL;
77
find_section (VeConfig *config, const char *name)
85
for (li = config->sections; li != NULL; li = li->next) {
86
VeSection *section = li->data;
87
if (strcmp (section->name, name) == 0)
94
free_line (VeLine *line)
96
g_free (line->fullkey);
98
g_free (line->string);
103
/* does not remove from parent->lines */
105
destroy_line (VeLine *line)
107
if (line->fullkey != NULL)
108
g_hash_table_remove (line->parent->config->line_ht,
115
destroy_section (VeSection *section)
117
g_free (section->name);
118
section->name = NULL;
120
g_list_foreach (section->lines, (GFunc) destroy_line, NULL);
121
g_list_free (section->lines);
122
section->lines = NULL;
128
new_section (VeConfig *config, const char *name)
130
VeSection *section = g_new0 (VeSection, 1);
131
section->config = config;
132
section->name = g_strdup (name);
137
add_text_line (VeConfig *config, VeSection *section, const char *text)
139
VeLine *line = g_new0 (VeLine, 1);
140
line->type = VE_LINE_TEXT;
141
line->parent = section;
142
line->string = g_strdup (text);
144
section->lines = g_list_append (section->lines, line);
147
/* Find first instance of this key where it is commented out, this
148
is likely where we want to insert this key */
150
find_commented_out (VeSection *section, VeLine *line)
153
int keylen = strlen (line->key);
155
for (li = section->lines; li != NULL; li = li->next) {
157
VeLine *ll = li->data;
158
if (ll->type != VE_LINE_TEXT)
161
while (*p == ' ' || *p == '\t')
166
while (*p == ' ' || *p == '\t')
168
if (strncmp (p, line->key, keylen) == 0 &&
178
/* append, but be nice to whitespace and comments */
180
careful_append (VeSection *section, VeLine *line)
184
gboolean seen_white = FALSE;
186
g_assert (line->type == VE_LINE_KEY);
188
li = find_commented_out (section, line);
190
if (li->next == NULL)
191
section->lines = g_list_append
192
(section->lines, line);
194
section->lines = g_list_insert_before
201
li = g_list_last (section->lines);
205
if (ll->type == VE_LINE_TEXT) {
206
if (ll->string[0] == '\0') {
208
} else if (seen_white) {
209
section->lines = g_list_insert_before
215
if (li->next == NULL)
216
section->lines = g_list_append
217
(section->lines, line);
219
section->lines = g_list_insert_before
227
section->lines = g_list_prepend (section->lines, line);
231
add_key_line (VeConfig *config, VeSection *section,
232
const char *key, const char *val,
233
gboolean careful_add)
235
VeLine *line = g_new0 (VeLine, 1);
236
line->type = VE_LINE_KEY;
237
line->parent = section;
238
if (section->name == NULL) {
239
line->fullkey = g_strdup (key);
240
line->key = line->fullkey;
242
line->fullkey = g_strdup_printf ("%s/%s",
245
line->key = strchr (line->fullkey, '/');
248
line->string = g_strdup (val);
251
if (g_hash_table_lookup (config->line_ht, line->fullkey) != NULL) {
256
if ( ! careful_add ||
257
section->lines == NULL) {
258
section->lines = g_list_append (section->lines, line);
260
careful_append (section, line);
263
g_hash_table_insert (config->line_ht,
269
get_mtime (const char *file)
272
if (g_stat (file, &s) == 0)
279
read_config (VeConfig *config)
282
VeSection *section = config->root;
287
config->mtime = get_mtime (config->file);
289
VE_IGNORE_EINTR (fp = fopen (config->file, "r"));
300
VE_IGNORE_EINTR (getsret = fgets (buf, sizeof (buf), fp));
304
p = strchr (buf, '\n');
308
while (*nows == ' ' || *nows == '\t')
311
p = strchr (nows, ']');
318
section = new_section (config, nows);
319
config->sections = g_list_append (config->sections,
321
} else if (*nows == '\0') {
322
add_text_line (config, section, "");
323
} else if (*nows == '#') {
324
add_text_line (config, section, buf);
325
} else if ((eq = strchr (nows, '=')) != NULL) {
329
val = g_strcompress (eq);
330
add_key_line (config, section,
333
FALSE /* careful_add */);
336
/* Note: all invalid lines are whacked from the file */
338
/* Note this is a hard limit to avoid run away files.
339
Do we really expect files longer then 5000 lines?
340
This is to be ultra anal for security's sake. */
346
VE_IGNORE_EINTR (fclose (fp));
350
find_line (VeConfig *config,
357
dkey = g_strdup (key);
358
p = strchr (dkey, '=');
362
line = g_hash_table_lookup (config->line_ht, dkey);
368
find_last_section (VeConfig *config)
372
if (config->sections == NULL)
375
li = g_list_last (config->sections);
380
find_or_make_section (VeConfig *config,
388
VeSection *last_sect;
390
dkey = g_strdup (key);
391
p = strchr (dkey, '=');
394
p = strchr (dkey, '/');
397
/* we're adding to the root which is completely
398
empty so add a blank line to separate it */
399
if (make_new && config->root->lines == NULL)
400
add_text_line (config, config->root, "");
405
*key_name = g_strdup (p+1);;
407
section = find_section (config, dkey);
408
if (section != NULL) {
418
/* Add an empty line on end of last section */
419
last_sect = find_last_section (config);
420
if (last_sect != config->root ||
421
config->root->lines != NULL)
422
add_text_line (config, last_sect, "");
424
section = new_section (config, dkey);
425
config->sections = g_list_append (config->sections, section);
433
ve_config_new (const char *file)
437
g_return_val_if_fail (file != NULL, NULL);
439
config = g_new0 (VeConfig, 1);
441
config->file = g_strdup (file);
442
config->root = new_section (config, NULL);
443
config->line_ht = g_hash_table_new (g_str_hash, g_str_equal);
445
read_config (config);
451
ve_config_get (const char *file)
453
VeConfig *config = NULL;
455
if (config_hash == NULL)
456
config_hash = g_hash_table_new (g_str_hash, g_str_equal);
458
config = g_hash_table_lookup (config_hash, file);
460
if (config == NULL) {
461
config = ve_config_new (file);
462
config->hashed = TRUE;
463
g_hash_table_insert (config_hash, g_strdup (file), config);
465
ve_config_recheck (config);
472
config_clear (VeConfig *config)
474
g_free (config->file);
477
destroy_section (config->root);
479
g_list_foreach (config->sections, (GFunc) destroy_section, NULL);
480
g_list_free (config->sections);
481
config->sections = NULL;
483
g_hash_table_destroy (config->line_ht);
484
config->line_ht = NULL;
486
memset (config, 0, sizeof (VeConfig));
490
ve_config_recheck (VeConfig *config)
492
time_t curtime = time (NULL);
494
g_return_if_fail (config != NULL);
496
/* don't check more then once a second,
497
* it would be pointless anyway */
498
if (config->last_recheck == curtime)
501
if (get_mtime (config->file) != config->mtime) {
502
char *file = g_strdup (config->file);
504
/* clear all data and null the structure */
505
config_clear (config);
507
/* reset the config file */
509
config->root = new_section (config, NULL);
510
config->line_ht = g_hash_table_new (g_str_hash, g_str_equal);
513
read_config (config);
516
config->last_recheck = curtime;
520
ve_config_destroy (VeConfig *config)
522
g_return_if_fail (config != NULL);
523
g_return_if_fail ( ! config->hashed);
525
config_clear (config);
531
strescape_but_high (const gchar *source)
537
g_return_val_if_fail (source != NULL, NULL);
539
p = (guchar *) source;
540
/* Each source byte needs maximally four destination chars (\000) */
541
q = dest = g_malloc (strlen (source) * 4 + 1);
576
*q++ = '0' + (((*p) >> 6) & 07);
577
*q++ = '0' + (((*p) >> 3) & 07);
578
*q++ = '0' + ((*p) & 07);
592
save_section (VeSection *section, FILE *fp)
595
for (li = section->lines; li != NULL; li = li->next) {
596
VeLine *line = li->data;
597
if (line->type == VE_LINE_TEXT) {
598
VE_IGNORE_EINTR (fprintf (fp, "%s\n", line->string));
599
} else if (line->type == VE_LINE_KEY) {
600
char *out = strescape_but_high (ve_sure_string (line->string));
601
VE_IGNORE_EINTR (fprintf (fp, "%s=%s\n",
610
ve_config_save (VeConfig *config, gboolean force)
615
g_return_val_if_fail (config != NULL, FALSE);
617
if ( ! force && ! config->dirty)
620
VE_IGNORE_EINTR (fp = fopen (config->file, "w"));
624
save_section (config->root, fp);
626
for (li = config->sections; li != NULL; li = li->next) {
627
VeSection *section = li->data;
628
VE_IGNORE_EINTR (fprintf (fp, "[%s]\n", section->name));
629
save_section (section, fp);
632
VE_IGNORE_EINTR (fclose (fp));
634
/* update the mtime */
635
config->mtime = get_mtime (config->file);
636
config->dirty = FALSE;
642
ve_config_get_translated_string (VeConfig *config,
651
g_return_val_if_fail (config != NULL, NULL);
652
g_return_val_if_fail (key != NULL, NULL);
654
dkey = g_strdup (key);
655
def = strchr (dkey, '=');
661
for (li = ve_i18n_get_language_list ("LC_MESSAGES");
664
char *full = g_strdup_printf ("%s[%s]", dkey, (char *)li->data);
665
line = g_hash_table_lookup (config->line_ht, full);
671
line = g_hash_table_lookup (config->line_ht, dkey);
674
ret = g_strdup (line->string);
676
ret = g_strdup (def);
682
ve_config_get_string (VeConfig *config,
690
g_return_val_if_fail (config != NULL, NULL);
691
g_return_val_if_fail (key != NULL, NULL);
693
dkey = g_strdup (key);
694
def = strchr (dkey, '=');
700
line = g_hash_table_lookup (config->line_ht, dkey);
703
ret = g_strdup (line->string);
705
ret = g_strdup (def);
712
ve_config_get_bool (VeConfig *config,
717
g_return_val_if_fail (config != NULL, FALSE);
718
g_return_val_if_fail (key != NULL, FALSE);
720
val = ve_config_get_string (config, key);
736
ve_config_get_int (VeConfig *config,
742
g_return_val_if_fail (config != NULL, 0);
743
g_return_val_if_fail (key != NULL, 0);
745
val = ve_config_get_string (config, key);
754
ve_config_set_string (VeConfig *config,
760
char *key_name = NULL;
762
g_return_if_fail (config != NULL);
763
g_return_if_fail (key != NULL);
764
g_return_if_fail (string != NULL);
766
config->dirty = TRUE;
768
line = find_line (config, key);
770
g_free (line->string);
771
line->string = g_strdup (string);
775
section = find_or_make_section (config, key, &key_name,
776
TRUE /* make_new */);
777
add_key_line (config, section, key_name, string,
778
TRUE /* careful_add */);
783
ve_config_set_bool (VeConfig *config,
789
char *key_name = NULL;
791
g_return_if_fail (config != NULL);
792
g_return_if_fail (key != NULL);
794
config->dirty = TRUE;
796
line = find_line (config, key);
798
g_free (line->string);
799
line->string = g_strdup (boolean ? "true" : "false");
803
section = find_or_make_section (config, key, &key_name,
804
TRUE /* make_new */);
805
add_key_line (config, section, key_name, boolean ? "true" : "false",
806
TRUE /* careful_add */);
811
ve_config_set_int (VeConfig *config,
817
char *key_name = NULL;
820
g_return_if_fail (config != NULL);
821
g_return_if_fail (key != NULL);
823
config->dirty = TRUE;
825
num = g_strdup_printf ("%d", integer);
827
line = find_line (config, key);
829
g_free (line->string);
834
section = find_or_make_section (config, key, &key_name,
835
TRUE /* make_new */);
836
add_key_line (config, section, key_name, num,
837
TRUE /* careful_add */);
843
ve_config_delete_section (VeConfig *config,
848
g_return_if_fail (config != NULL);
849
g_return_if_fail (section != NULL);
851
if (section == NULL) {
852
config->dirty = TRUE;
854
destroy_section (config->root);
855
config->root = new_section (config, NULL);
859
sec = find_section (config, section);
861
config->dirty = TRUE;
863
config->sections = g_list_remove (config->sections, sec);
864
destroy_section (sec);
869
ve_config_delete_key (VeConfig *config,
874
g_return_if_fail (config != NULL);
875
g_return_if_fail (key != NULL);
877
line = find_line (config, key);
879
config->dirty = TRUE;
881
line->parent->lines = g_list_remove (line->parent->lines,
888
ve_config_delete_translations (VeConfig *config, const char *key)
895
g_return_if_fail (config != NULL);
896
g_return_if_fail (key != NULL);
898
section = find_or_make_section (config, key, &key_name,
899
FALSE /* make_new */);
900
if (section == NULL) {
905
len = strlen (key_name);
906
lines = g_list_copy (section->lines);
907
for (li = lines; li != NULL; li = li->next) {
908
VeLine *line = li->data;
909
if (line->type == VE_LINE_KEY &&
910
strncmp (line->key, key_name, len) == 0 &&
911
line->key[len] == '[') {
912
config->dirty = TRUE;
914
section->lines = g_list_remove (section->lines, line);
922
ve_config_get_sections (VeConfig *config)
927
g_return_val_if_fail (config != NULL, NULL);
931
for (li = config->sections; li != NULL; li = li->next) {
932
VeSection *section = li->data;
933
list = g_list_prepend (list, g_strdup (section->name));
935
return g_list_reverse (list);
939
ve_config_get_keys (VeConfig *config, const char *section)
945
g_return_val_if_fail (config != NULL, NULL);
946
g_return_val_if_fail (section != NULL, NULL);
948
sec = find_section (config, section);
954
for (li = sec->lines; li != NULL; li = li->next) {
955
VeLine *ll = li->data;
956
if (ll->type == VE_LINE_KEY &&
957
! ve_string_empty (ll->key))
958
list = g_list_prepend (list, g_strdup (ll->key));
960
return g_list_reverse (list);
964
ve_config_free_list_of_strings (GList *list)
971
for (li = list; li != NULL; li = li->next) {