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.
47 * 'linestart': pointer to the line buffer.
48 * 'linecur': current pointer in the line string (same string than linestart).
50 * Return a pointer to the first token copied from buf in a allocated
51 * buffer which is correctly nil-terminated. Also fill *eatlen
52 * argument the length of eaten bytes. The user should free the token
53 * structure and the string after use. On error, return NULL.
55 static const char *append_token(struct line *line, const char *linestart,
59 const char *start, *s;
63 tok = strictmalloc(sizeof(struct token));
67 while (*s != '\0' && isspace(*s))
69 if (*s == '\0' || *s == '#')
72 tok->offset = linecur - linestart;
74 /* if it's a double quote, wait next double quote */
79 if (*s == '"' && *(s-1) != '\\')
84 return NULL; /* XXX free */
87 /* if it's a simple quote, wait next simple quote */
88 else if (*s == '\'') {
92 if (*s == '\'' && *(s-1) != '\\')
100 /* else wait a space */
103 while (*s != '\0' && !isspace(*s)) {
112 /* allocate string */
113 retbuf = strictmalloc(len + 1);
114 memcpy(retbuf, start, len);
117 /* fill token structure and append it in line */
119 //printf("Append <%s>\n", tok->str);
120 TAILQ_INSERT_TAIL(&line->token_list, tok, next);
131 * Parse the line contained in buffer 'buf'. This function fills a
132 * line structure, composed of several tokens.
134 static struct line *parse_conf_line(const char *linebuf)
137 const char *curbuf = linebuf;
139 line = strictmalloc(sizeof(struct line));
140 memset(line, 0, sizeof(struct line));
141 TAILQ_INIT(&line->token_list);
143 if (isspace(*linebuf))
144 line->start_with_space = 1;
146 /* read tokens from buf and append it to line structure */
148 curbuf = append_token(line, linebuf, curbuf);
153 int check_opt_name(const char *name)
160 /* return true if all dependancies are met to set the enable the
165 /* parse a line to get a "help" token */
166 int parse_help(const struct line *line)
170 tok = TAILQ_FIRST(&line->token_list);
172 return -1; /* should not happen */
174 if (!strcmp(tok->str, "help") && line->n_token == 1)
176 else if (!strcmp(tok->str, "---help---") && line->n_token == 1)
181 /* look if given line contains a "source" command, and execute the
182 * command if it's the case. Return 0 on success and -1 on error. XXX */
183 const char *source_file(const struct line *line)
187 tok = TAILQ_FIRST(&line->token_list);
189 return NULL; /* should not happen */
191 /* syntax is: source FILE_NAME */
192 if (!strcmp(tok->str, "source") && line->n_token == 2) {
193 tok = TAILQ_NEXT(tok, next);
194 //printf("source <%s>\n", tok->str);
201 * Parse the file given as argument and return a tree describing the
202 * configuration. XXX wrong
204 int parse_conf_file(const char *filename, struct confnode **pparent,
205 struct confnode **pcurrent)
213 struct confnode *current = *pcurrent;
214 struct confnode *parent = *pparent;
215 const char *sourcefilename;
218 /* XXX lookup in several PATHs */
219 f = fopen(filename, "r");
221 printf("cannot find file <%s>\n", filename);
224 while (fgets(buf, sizeof(buf), f) != NULL) {
227 /* printf("parent=%s: %s", parent->name, buf); */
229 /* we are reading help of an option, do it until the
230 * line does not starts with space */
231 if (read_help && (isspace(*buf) || line_is_empty(buf))) {
233 /* should not happen */
234 if (current == NULL) {
235 /* remove \n, display line # */
236 c = strchr(buf, '\n');
239 printf("%s:%d invalid line <%s>\n", filename, linenum, buf);
243 /* append string in buffer */
244 strncat(current->help, buf,
245 sizeof(current->help) - strlen(current->help) - 1);
251 /* skip empty / comments lines */
252 if (line_is_empty(buf))
256 line = parse_conf_line(buf);
258 /* XXX put all the following in a function */
261 /* if the line does not start with a space, it's a new
262 * keyword, so it's a new node */
263 if (!line->start_with_space) {
265 /* end of previous node */
266 if (current && current->flags & CONFNODE_F_IS_DIR) {
271 /* if it's a source command, parse the new
273 sourcefilename = source_file(line);
274 if (sourcefilename) {
275 if (parse_conf_file(sourcefilename, &parent, ¤t)) {
276 /* remove \n, display line # */
277 c = strchr(buf, '\n');
280 printf("%s:%d invalid line <%s>\n", filename,
287 /* if the command closes a menu */
288 if (confnode_close_dir(parent, line) == 0) {
289 parent = parent->parent;
293 /* if it's a new node command */
294 current = confnode_new(line);
296 current->parent = parent;
297 TAILQ_INSERT_TAIL(&parent->children, current, next);
301 /* remove \n, display line # */
302 c = strchr(buf, '\n');
305 printf("%s:%d invalid line <%s>\n", filename, linenum, buf);
310 /* see if it's a help indication */
311 if (parse_help(line) == 0) {
313 strcpy(current->help, "");
317 /* parse node attributes */
318 if (confnode_add_attr(current, line, buf) == 0)
321 /* remove \n, display line # */
322 c = strchr(buf, '\n');
325 printf("%s:%d invalid line <%s>\n", filename, linenum, buf);
330 while ( (tok = TAILQ_FIRST(&line->token_list)) ) {
331 TAILQ_REMOVE(&line->token_list, tok, next);
344 /* delete all stored values in conf tree */
345 void conf_reset(struct confnode *conf)
348 conf->value[0] = '\0';
349 TAILQ_FOREACH(c, &conf->children, next) {
355 * Free previous conf 'prev' if not NULL, then parse the Kconfig and
356 * the .config files. Fill the htable. Return the top node of the
357 * configuration tree. Return NULL on error.
359 struct confnode *conf_reset_and_read(struct confnode *prev,
360 const char *dotconfig_filename)
362 struct confnode *current, *parent;
363 struct confnode *root;
366 confnode_register_all();
368 root = confnode_new_root();
375 parse_conf_file("/home/zer0/projects/libcmdline/Kconfig",
378 parse_conf_file("/Users/zer0/projects/libcmdline/Kconfig",
381 conf_htable_fill(root);
382 if (dotconfig_read(dotconfig_filename, root) < 0)
383 printf("Cannot parse <%s>, use defaults\n", dotconfig_filename);