2 * Copyright (c) 2009, 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.
33 #include <sys/queue.h>
35 #include "strictmalloc.h"
36 #include "expression.h"
37 #include "conf_parser.h"
39 #include "conf_htable.h"
40 #include "parser_common.h"
41 #include "dotconfig.h"
45 * Add a token in the line structure given as argument.
46 * 'linestart' parameter is the beginning of the line buffer.
48 * Return a pointer to the first token copied from buf in a allocated
49 * buffer which is correctly nil-terminated. Also fill *eatlen
50 * argument the length of eaten bytes. The user should free the token
51 * structure and the string after use. On error, return NULL.
53 static const char *append_token(struct line *line, const char *linestart,
57 const char *start, *s;
61 tok = strictmalloc(sizeof(struct token));
65 while (*s != '\0' && isspace(*s))
67 if (*s == '\0' || *s == '#')
70 tok->offset = linecur - linestart;
72 /* if it's a double quote, wait next double quote */
77 if (*s == '"' && *(s-1) != '\\')
82 return NULL; /* XXX free */
85 /* if it's a simple quote, wait next simple quote */
86 else if (*s == '\'') {
90 if (*s == '\'' && *(s-1) != '\\')
98 /* else wait a space */
101 while (*s != '\0' && !isspace(*s)) {
110 /* allocate string */
111 retbuf = strictmalloc(len + 1);
112 memcpy(retbuf, start, len);
115 /* fill token structure and append it in line */
117 //printf("Append <%s>\n", tok->str);
118 TAILQ_INSERT_TAIL(&line->token_list, tok, next);
129 * Parse the line contained in buffer 'buf'. This function fills a
130 * line structure, composed of several tokens.
132 static struct line *parse_conf_line(const char *linebuf)
135 const char *curbuf = linebuf;
137 line = strictmalloc(sizeof(struct line));
138 memset(line, 0, sizeof(struct line));
139 TAILQ_INIT(&line->token_list);
141 if (isspace(*linebuf))
142 line->start_with_space = 1;
144 /* read tokens from buf and append it to line structure */
146 curbuf = append_token(line, linebuf, curbuf);
151 int check_opt_name(const char *name)
158 /* return true if all dependancies are met to set the enable the
163 /* parse a line to get a "help" token */
164 int parse_help(const struct line *line)
168 tok = TAILQ_FIRST(&line->token_list);
170 return -1; /* should not happen */
172 if (!strcmp(tok->str, "help") && line->n_token == 1)
174 else if (!strcmp(tok->str, "---help---") && line->n_token == 1)
179 /* look if given line contains a "source" command, and execute the
180 * command if it's the case. Return 0 on success and -1 on error. XXX */
181 const char *source_file(const struct line *line)
185 tok = TAILQ_FIRST(&line->token_list);
187 return NULL; /* should not happen */
189 /* syntax is: source FILE_NAME */
190 if (!strcmp(tok->str, "source") && line->n_token == 2) {
191 tok = TAILQ_NEXT(tok, next);
192 //printf("source <%s>\n", tok->str);
199 * Parse the file given as argument and return a tree describing the
200 * configuration. XXX wrong
202 int parse_conf_file(const char *filename, struct confnode **pparent,
203 struct confnode **pcurrent)
211 struct confnode *current = *pcurrent;
212 struct confnode *parent = *pparent;
213 const char *sourcefilename;
216 /* XXX lookup in several PATHs */
217 f = fopen(filename, "r");
219 printf("cannot find file <%s>\n", filename);
222 while (fgets(buf, sizeof(buf), f) != NULL) {
225 /* printf("parent=%s: %s", parent->name, buf); */
227 /* we are reading help of an option, do it until the
228 * line does not starts with space */
229 if (read_help && (isspace(*buf) || line_is_empty(buf))) {
231 /* should not happen */
232 if (current == NULL) {
233 /* remove \n, display line # */
234 c = strchr(buf, '\n');
237 printf("%s:%d invalid line <%s>\n", filename, linenum, buf);
241 /* append string in buffer */
242 strncat(current->help, buf,
243 sizeof(current->help) - strlen(current->help) - 1);
249 /* skip empty / comments lines */
250 if (line_is_empty(buf))
254 line = parse_conf_line(buf);
256 /* XXX put all the following in a function */
259 /* if the line does not start with a space, it's a new
260 * keyword, so it's a new node */
261 if (!line->start_with_space) {
263 /* end of previous node */
264 if (current && current->flags & CONFNODE_F_IS_DIR) {
269 /* if it's a source command, parse the new
271 sourcefilename = source_file(line);
272 if (sourcefilename) {
273 if (parse_conf_file(sourcefilename, &parent, ¤t)) {
274 /* remove \n, display line # */
275 c = strchr(buf, '\n');
278 printf("%s:%d invalid line <%s>\n", filename,
285 /* if the command closes a menu */
286 if (confnode_close_dir(parent, line) == 0) {
287 parent = parent->parent;
291 /* if it's a new node command */
292 current = confnode_new(line);
294 current->parent = parent;
295 TAILQ_INSERT_TAIL(&parent->children, current, next);
299 /* remove \n, display line # */
300 c = strchr(buf, '\n');
303 printf("%s:%d invalid line <%s>\n", filename, linenum, buf);
308 /* see if it's a help indication */
309 if (parse_help(line) == 0) {
311 strcpy(current->help, "");
315 /* parse node attributes */
316 if (confnode_add_attr(current, line, buf) == 0)
319 /* remove \n, display line # */
320 c = strchr(buf, '\n');
323 printf("%s:%d invalid line <%s>\n", filename, linenum, buf);
328 while ( (tok = TAILQ_FIRST(&line->token_list)) ) {
329 TAILQ_REMOVE(&line->token_list, tok, next);
342 /* delete all stored values in conf tree */
343 void conf_reset(struct confnode *conf)
346 conf->value[0] = '\0';
347 TAILQ_FOREACH(c, &conf->children, next) {
353 * Free previous conf 'prev' if not NULL, then parse the Kconfig and
354 * the .config files. Fill the htable. Return the top node of the
355 * configuration tree. Return NULL on error.
357 struct confnode *conf_reset_and_read(struct confnode *prev,
358 const char *dotconfig_filename)
360 struct confnode *current, *parent;
361 struct confnode *root;
364 confnode_register_all();
366 root = confnode_new_root();
373 parse_conf_file("/home/zer0/projects/libcmdline/Kconfig",
376 parse_conf_file("/Users/zer0/projects/libcmdline/Kconfig",
379 conf_htable_fill(root);
380 if (dotconfig_read(dotconfig_filename, root) < 0)
381 printf("Cannot parse <%s>, use defaults\n", dotconfig_filename);