Introduce command-line config utility
[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 <string.h>
25
26 #include "configfile.h"
27 #include "config.h"
28
29 /* The Browser Switchboard config file options */
30 struct swb_config_option swb_config_options[] = {
31         { "continuous_mode", SWB_CONFIG_OPT_INT, SWB_CONFIG_CONTINUOUS_MODE_SET },
32         { "default_browser", SWB_CONFIG_OPT_STRING, SWB_CONFIG_DEFAULT_BROWSER_SET },
33         { "other_browser_cmd", SWB_CONFIG_OPT_STRING, SWB_CONFIG_OTHER_BROWSER_CMD_SET },
34         { "logging", SWB_CONFIG_OPT_STRING, SWB_CONFIG_LOGGING_SET },
35         { NULL, 0, 0 },
36 };
37
38 /* Browser Switchboard configuration defaults */
39 static struct swb_config swb_config_defaults = {
40         .flags = SWB_CONFIG_INITIALIZED,
41         .continuous_mode = 0,
42         .default_browser = "microb",
43         .other_browser_cmd = NULL,
44         .logging = "stdout",
45 };
46
47
48 /* Copy the contents of an swb_config struct
49    The entries[] array means that the standard copy will not work */
50 void swb_config_copy(struct swb_config *dst, struct swb_config *src) {
51         if (!dst || !src)
52                 return;
53
54         dst->entries[0] = &(dst->continuous_mode);
55         dst->entries[1] = &(dst->default_browser);
56         dst->entries[2] = &(dst->other_browser_cmd);
57         dst->entries[3] = &(dst->logging);
58
59         dst->flags = src->flags;
60
61         dst->continuous_mode = src->continuous_mode;
62         dst->default_browser = src->default_browser;
63         dst->other_browser_cmd = src->other_browser_cmd;
64         dst->logging = src->logging;
65 }
66
67 /* Initialize a swb_config struct with configuration defaults */
68 void swb_config_init(struct swb_config *cfg) {
69         swb_config_copy(cfg, &swb_config_defaults);
70 }
71
72 /* Free all heap memory used in an swb_config struct
73    This MUST NOT be done if any of the strings are being used elsewhere! */
74 void swb_config_free(struct swb_config *cfg) {
75         if (!cfg)
76                 return;
77         if (!(cfg->flags & SWB_CONFIG_INITIALIZED))
78                 return;
79
80         if (cfg->flags & SWB_CONFIG_DEFAULT_BROWSER_SET) {
81                 free(cfg->default_browser);
82                 cfg->default_browser = NULL;
83         }
84         if (cfg->flags & SWB_CONFIG_OTHER_BROWSER_CMD_SET) {
85                 free(cfg->other_browser_cmd);
86                 cfg->other_browser_cmd = NULL;
87         }
88         if (cfg->flags & SWB_CONFIG_LOGGING_SET) {
89                 free(cfg->logging);
90                 cfg->logging = NULL;
91         }
92
93         cfg->flags = 0;
94 }
95
96 /* Load a value into the part of a struct swb_config indicated by name */
97 static int swb_config_load_option(struct swb_config *cfg,
98                                   char *name, char *value) {
99         int i;
100         struct swb_config_option opt;
101         int retval = 0;
102
103         for (i = 0; swb_config_options[i].name; ++i) {
104                 opt = swb_config_options[i];
105                 if (strcmp(name, opt.name))
106                         continue;
107
108                 if (!(cfg->flags & opt.set_mask)) {
109                         switch (opt.type) {
110                           case SWB_CONFIG_OPT_STRING:
111                                 *(char **)cfg->entries[i] = value;
112                                 break;
113                           case SWB_CONFIG_OPT_INT:
114                                 *(int *)cfg->entries[i] = atoi(value);
115                                 free(value);
116                                 break;
117                         }
118                         cfg->flags |= opt.set_mask;
119                 }
120                 retval = 1;
121                 break;
122         }
123
124         if (!retval)
125                 free(value);
126
127         return retval;
128 }
129
130 /* Read the config file and load settings into the provided swb_config struct
131    Caller is responsible for freeing allocated strings with free()
132    Returns true on success, false otherwise */
133 int swb_config_load(struct swb_config *cfg) {
134         FILE *fp;
135         struct swb_config_line line;
136
137         if (!cfg || !(cfg->flags & SWB_CONFIG_INITIALIZED))
138                 return 0;
139
140         if (!(fp = open_config_file()))
141                 goto out_noopen;
142
143         /* Parse the config file
144            TODO: should we handle errors differently than EOF? */
145         if (!parse_config_file_begin())
146                 goto out;
147         while (!parse_config_file_line(fp, &line)) {
148                 if (line.parsed)
149                         swb_config_load_option(cfg, line.key, line.value);
150                 free(line.key);
151         }
152         parse_config_file_end();
153
154 out:
155         fclose(fp);
156 out_noopen:
157         return 1;
158 }