Also register for path / on D-Bus
[browser-switch] / config.c
1 /*
2  * config.c -- configuration functions for Browser Switchboard
3  *
4  * Copyright (C) 2009-2010 Steven Luo
5  * Derived from a Python implementation by Jason Simpson and Steven Luo
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
20  * USA.
21  */
22
23 #include <stdlib.h>
24 #include <stddef.h>
25 #include <string.h>
26
27 #include "configfile.h"
28 #include "config.h"
29
30 /* The Browser Switchboard config file options */
31 struct swb_config_option swb_config_options[] = {
32         { "continuous_mode", SWB_CONFIG_OPT_INT, SWB_CONFIG_CONTINUOUS_MODE_SET, offsetof(struct swb_config, continuous_mode) },
33         { "default_browser", SWB_CONFIG_OPT_STRING, SWB_CONFIG_DEFAULT_BROWSER_SET, offsetof(struct swb_config, default_browser) },
34         { "other_browser_cmd", SWB_CONFIG_OPT_STRING, SWB_CONFIG_OTHER_BROWSER_CMD_SET, offsetof(struct swb_config, other_browser_cmd) },
35         { "logging", SWB_CONFIG_OPT_STRING, SWB_CONFIG_LOGGING_SET, offsetof(struct swb_config, logging) },
36         { "autostart_microb", SWB_CONFIG_OPT_INT, SWB_CONFIG_AUTOSTART_MICROB_SET, offsetof(struct swb_config, autostart_microb) },
37         { NULL, 0, 0, 0 },
38 };
39
40 /* Browser Switchboard configuration defaults */
41 static struct swb_config swb_config_defaults = {
42         .flags = SWB_CONFIG_INITIALIZED,
43         .continuous_mode = 1,
44         .default_browser = "microb",
45         .other_browser_cmd = NULL,
46         .logging = "stdout",
47         .autostart_microb = -1,
48 };
49
50
51 /* Initialize a swb_config struct with configuration defaults */
52 inline void swb_config_init(struct swb_config *cfg) {
53         *cfg = swb_config_defaults;
54 }
55
56 /* Free all heap memory used in an swb_config struct
57    This MUST NOT be done if any of the strings are being used elsewhere! */
58 void swb_config_free(struct swb_config *cfg) {
59         int i;
60         void *entry;
61
62         if (!cfg)
63                 return;
64         if (!(cfg->flags & SWB_CONFIG_INITIALIZED))
65                 return;
66
67         for (i = 0; swb_config_options[i].name; ++i) {
68                 entry = (char *)cfg + swb_config_options[i].offset;
69                 if (cfg->flags & swb_config_options[i].set_mask) {
70                         switch (swb_config_options[i].type) {
71                           case SWB_CONFIG_OPT_STRING:
72                                 free(*(char **)entry);
73                                 *(char **)entry = NULL;
74                                 break;
75                           default:
76                                 break;
77                         }
78                 }
79         }
80
81         cfg->flags = 0;
82 }
83
84 /* Load a value into the part of a struct swb_config indicated by name */
85 static int swb_config_load_option(struct swb_config *cfg,
86                                   char *name, char *value) {
87         struct swb_config_option *opt;
88         void *entry;
89
90         /* Search through list of recognized config options for a match */
91         for (opt = swb_config_options; opt->name; ++opt) {
92                 if (strcmp(name, opt->name))
93                         continue;
94
95                 if (!(cfg->flags & opt->set_mask)) {
96                         entry = (char *)cfg + opt->offset;
97                         switch (opt->type) {
98                           case SWB_CONFIG_OPT_STRING:
99                                 *(char **)entry = value;
100                                 break;
101                           case SWB_CONFIG_OPT_INT:
102                                 *(int *)entry = atoi(value);
103                                 free(value);
104                                 break;
105                         }
106                         cfg->flags |= opt->set_mask;
107                 } else {
108                         /* Option was repeated in the config file
109                            We want the first value, so ignore this one */
110                         free(value);
111                 }
112                 return 1;
113         }
114
115         /* Unrecognized config option */
116         free(value);
117         return 0;
118 }
119
120 /* Read the config file and load settings into the provided swb_config struct
121    Caller is responsible for freeing allocated strings with free()
122    Returns true on success, false otherwise */
123 int swb_config_load(struct swb_config *cfg) {
124         FILE *fp;
125         struct swb_config_line line;
126
127         if (!cfg || !(cfg->flags & SWB_CONFIG_INITIALIZED))
128                 return 0;
129
130         if (!(fp = open_config_file()))
131                 goto out_noopen;
132
133         /* Parse the config file
134            TODO: should we handle errors differently than EOF? */
135         if (!parse_config_file_begin())
136                 goto out;
137         while (!parse_config_file_line(fp, &line)) {
138                 if (line.parsed)
139                         swb_config_load_option(cfg, line.key, line.value);
140                 free(line.key);
141         }
142         parse_config_file_end();
143
144 out:
145         fclose(fp);
146 out_noopen:
147         return 1;
148 }