2 * Copyright (c) 2010, 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.
31 #include <sys/queue.h>
33 #include "strictmalloc.h"
34 #include "parser_common.h"
35 #include "expression.h"
36 #include "conf_parser.h"
39 extern void confnode_root_register(void);
40 extern void confnode_menu_register(void);
41 extern void confnode_config_register(void);
42 extern void confnode_intconfig_register(void);
43 extern void confnode_menuconfig_register(void);
44 extern void confnode_strconfig_register(void);
45 extern void confnode_choice_register(void);
46 extern void confnode_choiceconfig_register(void);
47 extern void confnode_if_register(void);
48 extern void confnode_comment_register(void);
50 /* global list of all configuration node types */
51 struct confnode_type_list confnode_type_list;
53 /* alloc a new confnode */
54 static struct confnode *confnode_alloc(void)
58 n = strictmalloc(sizeof(struct confnode));
59 TAILQ_INIT(&n->children);
60 TAILQ_INIT(&n->depend);
61 snprintf(n->name, sizeof(n->name), "NONAME");
62 snprintf(n->name, sizeof(n->name), "No prompt");
63 snprintf(n->help, sizeof(n->help), "No help available\n");
68 /* alloc a new root node */
69 struct confnode *confnode_new_root(void)
74 /* forge a dummy line */
77 l.start_with_space = 0;
79 TAILQ_INIT(&l.token_list);
80 TAILQ_INSERT_TAIL(&l.token_list, &t, next);
82 return confnode_new(&l);
85 /* Parse the line, and return a new confnode if the line is a valid
86 * new confnode line (example: "menuconfig FOO\n"). Else, return
88 struct confnode *confnode_new(const struct line *line)
90 struct confnode_type *cnt;
95 TAILQ_FOREACH(cnt, &confnode_type_list, next) {
96 if (cnt->ops.new == NULL) {
97 printf("No new() for confnode type\n");
100 if (cnt->ops.new(n, line) == 0)
109 /* Free the node given as argument, and all its associated data */
110 void confnode_free(struct confnode *n)
120 while ( (e = TAILQ_FIRST(&n->depend)) ) {
126 /* Parse a line structure (and its associated line buffer) to match an
127 * attribute of a confnode. Return 0 if the line matches, else return
128 * -1 if we cannot match a valid attribute. */
129 int confnode_add_attr(struct confnode *n, const struct line *line,
134 tok = TAILQ_FIRST(&line->token_list);
136 return -1; /* should not happen */
138 /* specific attribute */
139 if (n->ops->add_attr)
140 return n->ops->add_attr(n, line, linebuf);
142 /* syntax is: prompt "prompt content" */
143 if (!(n->flags & CONFNODE_F_NO_SET_PROMPT) &&
144 !strcmp(tok->str, "prompt") &&
145 line->n_token <= 2) {
146 if (line->n_token == 2) {
147 tok = TAILQ_NEXT(tok, next);
148 snprintf(n->prompt, sizeof(n->prompt),
153 /* syntax is: prompt "requires EXPRESSION" */
154 else if (!(n->flags & CONFNODE_F_NO_SET_DEPS) &&
155 !strcmp(tok->str, "requires") &&
159 tok = TAILQ_NEXT(tok, next);
160 tmp = strdup(linebuf + tok->offset);
161 e = parse_expression(tmp);
165 TAILQ_INSERT_TAIL(&n->depend, e, next);
168 /* XXX we could support expression here ? */
169 /* syntax is: prompt "default VALUE" */
170 else if (!(n->flags & CONFNODE_F_NO_SET_DEFAULT) &&
171 !strcmp(tok->str, "default") &&
172 line->n_token == 2) {
173 tok = TAILQ_NEXT(tok, next);
174 snprintf(n->default_value,
175 sizeof(n->default_value),
183 /* Parse a line and check if it closes the current node ,
184 * "endmenu" closes "menu" node): in this case return 0. Else, return
186 int confnode_close_dir(struct confnode *parent, const struct line *line)
188 if (parent->ops->close_dir)
189 return parent->ops->close_dir(parent, line);
194 /* write config value in file f in a dotconfig-like manner. Return 0
196 int confnode_dotconfig_write(const struct confnode *n, FILE *f)
199 const struct confnode *c;
201 const char *quote = "";
203 if (n->ops->dotconfig_write)
204 return n->ops->dotconfig_write(n, f);
206 if (confnode_get_value(n, buf, sizeof(buf)) < 0)
208 val = confnode_strvalue_to_boolvalue(n, buf);
213 if (fprintf(f, "# CONFIG_%s is not set\n", n->name) < 0)
218 if (n->flags & CONFNODE_F_QUOTE_VALUE)
220 if (fprintf(f, "CONFIG_%s=%s%s%s\n", n->name, quote, buf, quote) < 0)
223 TAILQ_FOREACH(c, &n->children, next) {
224 if (confnode_dotconfig_write(c, f) < 0)
230 /* Convert string value into boolean value (mainly used for
231 * dependancies). Return -1 on error, else return the boolean value (0
233 int confnode_strvalue_to_boolvalue(const struct confnode *n, const char *strvalue)
235 if (n->ops->strvalue_to_boolvalue)
236 return n->ops->strvalue_to_boolvalue(n, strvalue);
238 if (strcmp("n", strvalue) == 0)
240 if (strcmp("y", strvalue) == 0)
245 /* Set the string value of the node n. Return 0 on success, or -1 if
246 * the value cannot be set. */
247 int confnode_set_user_strvalue(struct confnode *n, const char *strvalue)
252 buf[BUFSIZ-1] = '\0';
253 strncpy(buf, strvalue, BUFSIZ-1);
255 if (remove_quote(buf, &start, &end) == 0)
258 if (n->ops->set_user_strvalue)
259 return n->ops->set_user_strvalue(n, buf+start);
264 /* Get the string value that the user asked to set for this node
265 * 'n'. This function does not check if dependancies are met. Return 0
266 * on success, in this case the string is copied in buffer 'buf' of
267 * len 'buflen'. Return -1 if the value cannot be read. */
268 int confnode_get_user_strvalue(const struct confnode *n, char *buf, unsigned buflen)
270 if (n->ops->get_user_strvalue)
271 return n->ops->get_user_strvalue(n, buf, buflen);
276 /* Get user boolean value of the node. Return 0 if disabled, 1 if
277 * enabled, and -1 on error. */
278 int confnode_get_user_boolvalue(const struct confnode *n)
283 ret = confnode_get_user_strvalue(n, buf, sizeof(buf));
286 ret = confnode_strvalue_to_boolvalue(n, buf);
293 /* Set the default string value of the node n. Return 0 on success, or
294 * -1 if the value cannot be set. */
295 int confnode_set_default_strvalue(struct confnode *n, const char *strvalue)
300 buf[BUFSIZ-1] = '\0';
301 strncpy(buf, strvalue, BUFSIZ-1);
303 if (remove_quote(buf, &start, &end) == 0)
306 if (n->ops->set_default_strvalue)
307 return n->ops->set_default_strvalue(n, buf);
312 /* Get the default string value for this node 'n'. This function does
313 * not check if dependancies are met. Return 0 on success, in this
314 * case the string is copied in buffer 'buf' of len 'buflen'. Return
315 * -1 if the value cannot be read. */
316 int confnode_get_default_strvalue(const struct confnode *n, char *buf, unsigned buflen)
318 if (n->ops->get_default_strvalue)
319 return n->ops->get_default_strvalue(n, buf, buflen);
325 * Check deps to see if a node 'n' can be enabled. If yes, return 1,
326 * else return 0. On error, return -1. If 'verbose' is true, dump an
327 * error for each condition preventing node to be enabled.
329 int confnode_check_deps(const struct confnode *n, int verbose)
332 const struct confnode *pn = n->parent;
335 const char *parent_name;
337 /* bypass dependency checks if this flag is set */
338 if (n->flags & CONFNODE_F_NO_DEPS)
341 /* check that there is no disabled "if" or "menuconfig" above
343 for (pn = n->parent; pn; pn = pn->parent) {
344 if (pn->flags & CONFNODE_F_IS_ROOT)
346 if (!(pn->flags & CONFNODE_F_FORCE_CHILD_DEPS))
348 if (confnode_get_boolvalue(pn) != 0)
352 /* use value if node has no name */
353 if (pn->flags & CONFNODE_F_NO_NAME)
354 parent_name = pn->value;
356 parent_name = pn->name;
357 printf("cannot enable %s, depends on "
360 confnode_get_type_str(pn),
367 TAILQ_FOREACH(e, &n->depend, next) {
368 if (expression_eval(e))
371 if (expression_to_str(e, buf, sizeof(buf)) < 0)
374 printf("cannot enable %s, depends on %s\n", n->name, buf);
381 /* Get string value of a node, including dep check. Return -1 on
382 * error. Return the boolean value of the node (0 or 1) on success: in
383 * this case, and if buf is not NULL, buf is filled with the strvalue. */
384 int confnode_get_value(const struct confnode *n, char *buf, unsigned buflen)
386 int dep, ret, strvalue_len;
387 char localbuf[BUFSIZ];
392 strvalue_len = buflen;
396 strvalue_len = sizeof(localbuf);
399 /* check deps first */
400 dep = confnode_check_deps(n, 0);
406 ret = confnode_get_user_strvalue(n, strvalue, strvalue_len);
408 ret = confnode_get_default_strvalue(n, strvalue, strvalue_len);
410 return 0; /* consider the value as false */
412 ret = confnode_strvalue_to_boolvalue(n, strvalue);
419 /* Get boolean value of a node, including dep check. Return -1 on
420 * error. Return the boolean value of the node (0 or 1) on success. */
421 int confnode_get_boolvalue(const struct confnode *n)
423 return confnode_get_value(n, NULL, 0);
427 /* Return a string identifying the node type ("config", "menuconfig",
429 const char *confnode_get_type_str(const struct confnode *n)
431 if (n->ops->get_type_str)
432 return n->ops->get_type_str(n);
436 /* Print a one-line summary of the node. Used in case of 'ls'. */
437 void confnode_display_short(const struct confnode *n)
439 if (n->ops->display_short)
440 n->ops->display_short(n);
442 printf("------ %s\n", n->prompt);
445 /* Print a detailed view of the node. */
446 void confnode_display_long(const struct confnode *n)
448 const char *nodetype;
449 char value[MAX_VALUE_SIZE];
450 char default_value[MAX_VALUE_SIZE];
451 const char *quote = "";
453 if (n->ops->display_long) {
454 n->ops->display_long(n);
458 nodetype = confnode_get_type_str(n);
459 printf("%s <%s>\n", nodetype, n->name);
461 conf_display_path(n);
463 if (n->flags & CONFNODE_F_QUOTE_VALUE)
466 /* display real value */
467 if (confnode_get_value(n, value, sizeof(value)) < 0)
468 snprintf(value, sizeof(value), "invalid");
469 printf(" value %s%s%s\n", quote, value, quote);
471 /* display user value */
472 if (!strcmp(n->value, ""))
473 printf(" user NONE\n");
475 printf(" user %s%s%s\n", quote, n->value, quote);
477 /* display default value */
478 confnode_get_default_strvalue(n, default_value, MAX_VALUE_SIZE);
479 printf(" default %s%s%s\n", quote, default_value, quote);
481 /* check and display deps */
482 confnode_check_deps(n, 1);
485 static void __conf_display_path(const struct confnode *n, int first)
488 __conf_display_path(n->parent, 0);
489 if (n->flags & CONFNODE_F_IS_ROOT)
491 else if (!(n->flags & CONFNODE_F_INVISIBLE))
492 printf("%s%s", n->name, first ? "" : "/" );
495 /* show path: used by the 'pwd' command. Nodes like 'if' are
497 void conf_display_path(const struct confnode *n)
499 __conf_display_path(n, 1);
503 void confnode_register_all(void)
505 TAILQ_INIT(&confnode_type_list);
506 confnode_root_register();
507 confnode_menu_register();
508 confnode_config_register();
509 confnode_intconfig_register();
510 confnode_menuconfig_register();
511 confnode_strconfig_register();
512 confnode_choice_register();
513 confnode_choiceconfig_register();
514 confnode_if_register();
515 confnode_comment_register();