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.
33 #include <sys/queue.h>
36 #include "cfzy_list.h"
37 #include "cfzy_expr.h"
38 #include "cfzy_confnode.h"
40 #define LOG(level, fmt, args...) \
41 CFZY_LOG("confnode_choice", level, fmt, ##args)
43 /* Return a string identifying the node type ("config", "menuconfig",
45 static const char *choice_get_type_str(const struct cfzy_confnode *n)
51 static int choice_str2bool(const struct cfzy_confnode *n, const char *value)
53 struct cfzy_confnode *c;
55 /* NULL means "disabled" */
59 /* if we have no children, it's because we are creating the
60 * node, so accept all values, we will check them later in
62 if (TAILQ_EMPTY(&n->children))
65 /* else, the value must be the name of a children */
66 TAILQ_FOREACH(c, &n->children, child_next) {
67 if (!strcmp(value, c->name))
75 static int choice_close(struct cfzy_confnode *n)
77 struct cfzy_confnode_defvalue *defval;
78 struct cfzy_list_elt *e;
79 struct cfzy_confnode *c;
83 /* browse all default values and call choice_str2bool() on
84 * them to check that they are correct */
85 TAILQ_FOREACH(e, n->default_val_list, next) {
88 if (choice_str2bool(n, defval->val) < 0) {
89 LOG(ERR, "invalid default value <%s> for node <%s>\n",
90 defval->val, n->name);
94 if (choice_str2bool(n, n->default_value) < 0) {
95 LOG(ERR, "invalid default value <%s> for node <%s>\n",
96 n->default_value, n->name);
100 /* for each child node */
101 TAILQ_FOREACH(c, &n->children, child_next) {
103 /* set default value */
104 if (!strcmp(n->default_value, c->name))
105 c->default_value = strdup("y");
107 c->default_value = strdup("n");
109 if (c->default_value == NULL) {
110 LOG(ERR, "cannot allocate default value>\n");
114 /* set conditional default values for child nodes with
115 * the same condition */
116 TAILQ_FOREACH(e, n->default_val_list, next) {
119 if (cfzy_expr_to_str(defval->expr, exprbuf,
120 sizeof(exprbuf)) < 0) {
121 LOG(ERR, "cannot convert expression to str\n");
125 if (!strcmp(defval->val, c->name))
126 ret = cfzy_confnode_add_defval(c, "y", exprbuf);
128 ret = cfzy_confnode_add_defval(c, "n", exprbuf);
131 LOG(ERR, "cannot add conditional default\n");
141 static int choice_set_uservalue(struct cfzy_confnode *n, const char *value)
143 struct cfzy_confnode *c;
146 /* if value is NULL, unset this node and all its children,
147 * falling back to default value */
150 if (n->user_value != NULL)
152 n->user_value = NULL;
155 TAILQ_FOREACH(c, &n->children, child_next) {
156 if (c->user_value != NULL)
158 c->user_value = NULL;
163 /* if not NULL, the value must be the name of a children */
164 TAILQ_FOREACH(c, &n->children, child_next) {
165 if (!strcmp(value, c->name))
173 if (n->user_value != NULL)
175 n->user_value = strdup(c->name);
176 if (n->user_value == NULL) {
177 LOG(ERR, "cannot allocate value\n");
182 TAILQ_FOREACH(c, &n->children, child_next) {
183 if (!strcmp(value, c->name))
184 newvalue = strdup("y");
186 newvalue = strdup("n");
188 if (newvalue == NULL) {
189 LOG(ERR, "cannot allocate value\n");
193 if (c->user_value != NULL)
195 c->user_value = newvalue;
201 static struct cfzy_confnode_ops choice_ops = {
204 .close = choice_close,
205 .dotconfig_write = NULL,
207 .str2bool = choice_str2bool,
208 .get_type_str = choice_get_type_str,
209 .set_uservalue = choice_set_uservalue,
212 /* Create a new node */
213 enum cfzy_parse_return cfzy_confnode_choice_new(struct cfzy_confnode *n,
214 const struct cfzy_token_list *tklist)
216 struct cfzy_token *tok;
217 tok = TAILQ_FIRST(&tklist->list);
219 if (strcmp(tok->str, "choice") || tklist->n_token != 2)
222 tok = TAILQ_NEXT(tok, next);
223 n->ops = &choice_ops;
224 n->flags = CFZY_F_IS_DIR | CFZY_F_QUOTE_VAL;
226 n->name = strdup(tok->str);