better parsing errors
[dana/openbox.git] / openbox / config.c
1 #include "config.h"
2
3 #ifdef HAVE_STDIO_H
4 #  include <stdio.h>
5 #endif
6
7 static void config_free_entry(ConfigEntry *entry);
8 static void config_set_entry(char *name, ConfigValueType type,
9                              ConfigValue value);
10 static void config_def_free(ConfigDefEntry *entry);
11 static void print_config(GQuark q, gpointer data, gpointer fonk){
12     ConfigDefEntry *e = (ConfigDefEntry *)data;
13     g_message("config: %s %d", e->name, e->hasList);
14 }
15
16 static GData *config = NULL;
17 static GData *config_def = NULL;
18
19 /* provided by cparse.l */
20 void cparse_go(char *filename, FILE *);
21
22
23 void config_startup()
24 {
25     /* set up options exported by the kernel */
26     config_def_set(config_def_new("engine", Config_String,
27                                   "Engine",
28                                   "The name of the theming engine to be used "
29                                   "to decorate windows."));
30     config_def_set(config_def_new("theme", Config_String,
31                                   "Theme",
32                                   "The name of the theme to load with the "
33                                   "chosen engine."));
34     config_def_set(config_def_new("font", Config_String,
35                                   "Titlebar Font",
36                                   "The fontstring specifying the font to "
37                                   "be used in window titlebars."));
38     config_def_set(config_def_new("font.shadow", Config_Bool,
39                                   "Titlebar Font Shadow",
40                                   "Whether or not the text in the window "
41                                   "titlebars gets a drop shadow."));
42     config_def_set(config_def_new("font.shadow.offset", Config_Integer,
43                                   "Titlebar Font Shadow Offset",
44                                   "The offset of the drop shadow for text "
45                                   "in the window titlebars."));
46     config_def_set(config_def_new("titlebar.layout", Config_String,
47                                   "Titlebar Layout",
48                                   "The ordering of the elements in the "
49                                   "window titlebars."));
50
51     /*g_datalist_foreach(&config_def, print_config, NULL);*/
52 }
53
54 void config_shutdown()
55 {
56     g_datalist_clear(&config);
57     g_datalist_clear(&config_def);
58 }
59
60 void config_parse()
61 {
62     FILE *file;
63     char *path;
64     gboolean load = FALSE;
65
66     /* load the user rc */
67     path = g_build_filename(g_get_home_dir(), ".openbox", "rc3", NULL);
68     if ((file = fopen(path, "r")) != NULL) {
69         cparse_go(path, file);
70         fclose(file);
71         load = TRUE;
72     }
73     g_free(path);
74
75     if (!load) {
76         /* load the system wide rc */
77         path = g_build_filename(RCDIR, "rc3", NULL);
78         if ((file = fopen(path, "r")) != NULL) {
79             /*cparse_go(path, file);*/
80             fclose(file);
81         }
82         g_free(path);
83     }
84 }
85
86 gboolean config_set(char *name, ConfigValueType type, ConfigValue value)
87 {
88     ConfigDefEntry *def;
89     gboolean ret = FALSE;
90
91     name = g_ascii_strdown(name, -1);
92
93     /*g_datalist_foreach(&config_def, print_config, NULL);*/
94     def = g_datalist_get_data(&config_def, name);
95
96     if (def == NULL) {
97         g_warning("Invalid config option '%s'", name);
98     } else {
99         if (def->hasList) {
100             gboolean found = FALSE;
101             GSList *it;
102
103             it = def->values;
104             g_assert(it != NULL);
105             do {
106                 if (g_ascii_strcasecmp(it->data, value.string) == 0) {
107                     found = TRUE;
108                     break;
109                 }
110             } while ((it = it->next));
111
112             if (!found)
113                 g_warning("Invalid value '%s' for config option '%s'",
114                           value.string, name);
115             else
116                 ret = TRUE;
117         } else if (type != def->type) {
118             g_warning("Incorrect type of value for config option '%s'", name);
119         } else
120             ret = TRUE;
121
122     }
123
124     if (ret)
125         config_set_entry(name, type, value);
126     else
127         g_free(name);
128
129     return ret;
130 }
131
132 gboolean config_get(char *name, ConfigValueType type, ConfigValue *value)
133 {
134     ConfigEntry *entry;
135     gboolean ret = FALSE;
136
137     name = g_ascii_strdown(name, -1);
138     entry = g_datalist_get_data(&config, name);
139     if (entry != NULL && entry->type == type) {
140         *value = entry->value;
141         ret = TRUE;
142     }
143     g_free(name);
144     return ret;
145 }
146
147 static void config_set_entry(char *name, ConfigValueType type,
148                              ConfigValue value)
149 {
150     ConfigEntry *entry = NULL;
151
152     entry = g_new(ConfigEntry, 1);
153     entry->name = name;
154     entry->type = type;
155     if (type == Config_String)
156         entry->value.string = g_strdup(value.string);
157     else
158         entry->value = value;
159
160     g_datalist_set_data_full(&config, name, entry,
161                              (GDestroyNotify)config_free_entry);
162 }
163
164 static void config_free_entry(ConfigEntry *entry)
165 {
166     g_free(entry->name);
167     entry->name = NULL;
168     if(entry->type == Config_String) {
169         g_free(entry->value.string);
170         entry->value.string = NULL;
171     }
172     g_free(entry);
173 }
174
175 ConfigDefEntry *config_def_new(char *name, ConfigValueType type,
176                                 char *descriptive_name, char *long_description)
177 {
178     ConfigDefEntry *entry;
179
180     entry = g_new(ConfigDefEntry, 1);
181     entry->name = g_ascii_strdown(name, -1);
182     entry->descriptive_name = g_strdup(descriptive_name);
183     entry->long_description = g_strdup(long_description);
184     entry->hasList = FALSE;
185     entry->type = type;
186     entry->values = NULL;
187     return entry;
188 }
189
190 static void config_def_free(ConfigDefEntry *entry)
191 {
192     GSList *it;
193
194     g_free(entry->name);
195     g_free(entry->descriptive_name);
196     g_free(entry->long_description);
197     if (entry->hasList) {
198         for (it = entry->values; it != NULL; it = it->next)
199             g_free(it->data);
200         g_slist_free(entry->values);
201     }
202     g_free(entry);
203 }
204
205 gboolean config_def_add_value(ConfigDefEntry *entry, char *value)
206 {
207     if (entry->type != Config_String) {
208         g_warning("Tried adding value to non-string config definition");
209         return FALSE;
210     }
211
212     entry->hasList = TRUE;
213     entry->values = g_slist_append(entry->values, g_ascii_strdown(value, -1));
214     return TRUE;
215 }
216
217 gboolean config_def_set(ConfigDefEntry *entry)
218 {
219     gboolean ret = FALSE;
220     ConfigDefEntry *def;
221
222     if ((def = g_datalist_get_data(&config_def, entry->name))) {
223         g_assert(def != entry); /* adding it twice!? */
224         g_warning("Definition already set for config option '%s'. ",
225                   entry->name);
226         config_def_free(entry);
227     } else {
228         g_datalist_set_data_full(&config_def, entry->name, entry,
229                                  (GDestroyNotify)config_def_free);
230         ret = TRUE;
231     }
232
233     return ret;
234 }