2 * Copyright (c) 2013, Olivier MATZ <zer0@droids-corp.org>
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the University of California, Berkeley nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 #include "cfzy_htable.h"
36 #include "cfzy_string.h"
37 #include "cfzy_file.h"
38 #include "cfzy_conftree.h"
39 #include "cfzy_confnode.h"
41 #define LOG(level, fmt, args...) \
42 CFZY_LOG("dotconfig", level, fmt, ##args)
44 /* Allocate and return string containing the value of the
45 * option. Buffer must point to the option (after the '=' in the
46 * .config), and it can be quoted. The string must be freed by the
48 static char *dotconfig_get_optval(const char *buf)
56 while (*s != '\0' && isspace(*s))
58 if (*s == '\0' || *s == '#')
61 /* if it's a quote, unquote the string */
62 if (*s == '"' || *s == '\'') {
63 retbuf = cfzy_string_unquote(s, &len);
70 for (i = 0; s[i] != '\0' && s[i] != '\n' && s[i] != '#'; i ++)
78 /* parse a line of .config: fill the uservalue of nodes in the
79 * conftree structure */
80 static int dotconfig_parse_line(struct cfzy_conftree *conftree, const char *line)
82 struct cfzy_confnode *n;
87 /* copy line in a writable buffer */
88 buf[sizeof(buf) - 1] = '\0';
89 strncpy(buf, line, sizeof(buf) - 1);
93 while (*s != '\0' && isspace(*s))
96 /* nothing to do, empty line */
100 /* skip the first "#", expecting "is not set" */
103 while (*s != '\0' && isspace(*s))
106 /* nothing to do, it's a comment */
110 /* get node name, ignore invalid names */
111 if (strncmp("CONFIG_", s, strlen("CONFIG_")))
113 nodename = s + strlen("CONFIG_");
117 while (*s != '\0' && !isspace(*s))
120 /* nothing to do, it's a comment */
127 /* should end with "is not set", else it's a comment */
128 if (strcmp(s, "is not set\n"))
131 optval = strdup("n");
136 /* get node name, ignore invalid names */
137 if (strncmp("CONFIG_", s, strlen("CONFIG_")))
139 nodename = s + strlen("CONFIG_");
141 while (*s != '\0' && *s != '=')
148 optval = dotconfig_get_optval(s + 1);
153 /* find the node in the conf htable */
154 n = cfzy_htable_lookup(conftree->nodes_htable, nodename);
156 LOG(NOTICE, "ignore unknown symbol <%s>\n", nodename);
161 /* check that value is valid */
162 if (cfzy_confnode_str2bool(n, optval) < 0) {
163 LOG(ERR, "invalid option value %s=<%s>\n", nodename, optval);
168 /* set value in node */
169 LOG(DEBUG, "%s=<%s>\n", nodename, optval);
170 if (cfzy_confnode_set_uservalue(n, optval) < 0) {
171 LOG(ERR, "cannot set value %s=<%s>\n", nodename, optval);
181 int cfzy_dotconfig_read(struct cfzy_conftree *conftree, const char *filename)
187 LOG(INFO, "dotconfig read <%s>\n", filename);
189 f = fopen(filename, "r");
191 LOG(ERR, "cannot find file <%s>\n", filename);
194 while (fgets(buf, sizeof(buf), f) != NULL) {
196 if (dotconfig_parse_line(conftree, buf) < 0) {
207 int cfzy_dotconfig_write(const struct cfzy_conftree *conftree,
208 const char *filename)
211 const struct cfzy_confnode *c;
214 LOG(INFO, "open old dotconfig <%s>\n", filename);
216 /* open old file in read mode */
218 f = fopen(filename, "r");
219 if (f == NULL && errno != ENOENT) {
220 printf("cannot open file <%s>: %s\n",
221 filename, strerror(errno));
225 /* old file exists */
228 /* write C header in temp file */
231 printf("cannot open temp file\n");
235 /* dump all the children of root node */
236 TAILQ_FOREACH(c, &conftree->root->children, child_next) {
237 ret = cfzy_confnode_dotconfig_write(c, tmp_f);
242 /* files are the same, nothing to do */
243 if (cfzy_file_compare(f, tmp_f) == 0) {
244 LOG(INFO, "already up to date: <%s>\n", filename);
254 /* reopen the file in write mode */
256 LOG(INFO, "write new C header <%s>\n", filename);
258 f = fopen(filename, "w");
260 LOG(ERR, "cannot open file <%s>\n", filename);
264 /* dump all the children of root node */
265 TAILQ_FOREACH(c, &conftree->root->children, child_next) {
266 ret = cfzy_confnode_dotconfig_write(c, f);