-rw-r--r-- | scripts/kconfig/menu.c | 194 |
1 files changed, 141 insertions, 53 deletions
diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c index 24be0ec..1631767 100644 --- a/scripts/kconfig/menu.c +++ b/scripts/kconfig/menu.c | |||
@@ -49,138 +49,155 @@ void menu_add_menu(void) | |||
49 | } | 49 | } |
50 | 50 | ||
51 | void menu_end_menu(void) | 51 | void menu_end_menu(void) |
52 | { | 52 | { |
53 | last_entry_ptr = ¤t_menu->next; | 53 | last_entry_ptr = ¤t_menu->next; |
54 | current_menu = current_menu->parent; | 54 | current_menu = current_menu->parent; |
55 | } | 55 | } |
56 | 56 | ||
57 | struct expr *menu_check_dep(struct expr *e) | ||
58 | { | ||
59 | if (!e) | ||
60 | return e; | ||
61 | |||
62 | switch (e->type) { | ||
63 | case E_NOT: | ||
64 | e->left.expr = menu_check_dep(e->left.expr); | ||
65 | break; | ||
66 | case E_OR: | ||
67 | case E_AND: | ||
68 | e->left.expr = menu_check_dep(e->left.expr); | ||
69 | e->right.expr = menu_check_dep(e->right.expr); | ||
70 | break; | ||
71 | case E_SYMBOL: | ||
72 | /* change 'm' into 'm' && MODULES */ | ||
73 | if (e->left.sym == &symbol_mod) | ||
74 | return expr_alloc_and(e, expr_alloc_symbol(modules_sym)); | ||
75 | break; | ||
76 | default: | ||
77 | break; | ||
78 | } | ||
79 | return e; | ||
80 | } | ||
81 | |||
57 | void menu_add_dep(struct expr *dep) | 82 | void menu_add_dep(struct expr *dep) |
58 | { | 83 | { |
59 | current_entry->dep = expr_alloc_and(current_entry->dep, dep); | 84 | current_entry->dep = expr_alloc_and(current_entry->dep, menu_check_dep(dep)); |
60 | } | 85 | } |
61 | 86 | ||
62 | void menu_set_type(int type) | 87 | void menu_set_type(int type) |
63 | { | 88 | { |
64 | struct symbol *sym = current_entry->sym; | 89 | struct symbol *sym = current_entry->sym; |
65 | 90 | ||
66 | if (sym->type == type) | 91 | if (sym->type == type) |
67 | return; | 92 | return; |
68 | if (sym->type == S_UNKNOWN) { | 93 | if (sym->type == S_UNKNOWN) { |
69 | sym->type = type; | 94 | sym->type = type; |
70 | return; | 95 | return; |
71 | } | 96 | } |
72 | fprintf(stderr, "%s:%d: type of '%s' redefined from '%s' to '%s'\n", | 97 | fprintf(stderr, "%s:%d:warning: type of '%s' redefined from '%s' to '%s'\n", |
73 | current_entry->file->name, current_entry->lineno, | 98 | current_entry->file->name, current_entry->lineno, |
74 | sym->name ? sym->name : "<choice>", sym_type_name(sym->type), sym_type_name(type)); | 99 | sym->name ? sym->name : "<choice>", sym_type_name(sym->type), sym_type_name(type)); |
75 | } | 100 | } |
76 | 101 | ||
77 | struct property *create_prop(enum prop_type type) | 102 | struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep) |
78 | { | ||
79 | struct property *prop; | ||
80 | |||
81 | prop = malloc(sizeof(*prop)); | ||
82 | memset(prop, 0, sizeof(*prop)); | ||
83 | prop->type = type; | ||
84 | prop->file = current_file; | ||
85 | prop->lineno = zconf_lineno(); | ||
86 | |||
87 | return prop; | ||
88 | } | ||
89 | |||
90 | struct property *menu_add_prop(int token, char *prompt, struct symbol *def, struct expr *dep) | ||
91 | { | 103 | { |
92 | struct property *prop = create_prop(token); | 104 | struct property *prop = prop_alloc(type, current_entry->sym); |
93 | struct property **propp; | ||
94 | 105 | ||
95 | prop->sym = current_entry->sym; | ||
96 | prop->menu = current_entry; | 106 | prop->menu = current_entry; |
97 | prop->text = prompt; | 107 | prop->text = prompt; |
98 | prop->def = def; | 108 | prop->expr = expr; |
99 | E_EXPR(prop->visible) = dep; | 109 | prop->visible.expr = menu_check_dep(dep); |
100 | 110 | ||
101 | if (prompt) | 111 | if (prompt) { |
112 | if (current_entry->prompt) | ||
113 | fprintf(stderr, "%s:%d: prompt redefined\n", | ||
114 | current_entry->file->name, current_entry->lineno); | ||
102 | current_entry->prompt = prop; | 115 | current_entry->prompt = prop; |
103 | |||
104 | /* append property to the prop list of symbol */ | ||
105 | if (prop->sym) { | ||
106 | for (propp = &prop->sym->prop; *propp; propp = &(*propp)->next) | ||
107 | ; | ||
108 | *propp = prop; | ||
109 | } | 116 | } |
110 | 117 | ||
111 | return prop; | 118 | return prop; |
112 | } | 119 | } |
113 | 120 | ||
114 | void menu_add_prompt(int token, char *prompt, struct expr *dep) | 121 | void menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep) |
115 | { | 122 | { |
116 | current_entry->prompt = menu_add_prop(token, prompt, NULL, dep); | 123 | menu_add_prop(type, prompt, NULL, dep); |
117 | } | 124 | } |
118 | 125 | ||
119 | void menu_add_default(int token, struct symbol *def, struct expr *dep) | 126 | void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep) |
120 | { | 127 | { |
121 | current_entry->prompt = menu_add_prop(token, NULL, def, dep); | 128 | menu_add_prop(type, NULL, expr, dep); |
129 | } | ||
130 | |||
131 | void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep) | ||
132 | { | ||
133 | menu_add_prop(type, NULL, expr_alloc_symbol(sym), dep); | ||
122 | } | 134 | } |
123 | 135 | ||
124 | void menu_finalize(struct menu *parent) | 136 | void menu_finalize(struct menu *parent) |
125 | { | 137 | { |
126 | struct menu *menu, *last_menu; | 138 | struct menu *menu, *last_menu; |
127 | struct symbol *sym; | 139 | struct symbol *sym; |
128 | struct property *prop; | 140 | struct property *prop; |
129 | struct expr *parentdep, *basedep, *dep, *dep2; | 141 | struct expr *parentdep, *basedep, *dep, *dep2, **ep; |
130 | 142 | ||
131 | sym = parent->sym; | 143 | sym = parent->sym; |
132 | if (parent->list) { | 144 | if (parent->list) { |
133 | if (sym && sym_is_choice(sym)) { | 145 | if (sym && sym_is_choice(sym)) { |
134 | /* find the first choice value and find out choice type */ | 146 | /* find the first choice value and find out choice type */ |
135 | for (menu = parent->list; menu; menu = menu->next) { | 147 | for (menu = parent->list; menu; menu = menu->next) { |
136 | if (menu->sym) { | 148 | if (menu->sym) { |
137 | current_entry = parent; | 149 | current_entry = parent; |
138 | menu_set_type(menu->sym->type); | 150 | menu_set_type(menu->sym->type); |
139 | current_entry = menu; | 151 | current_entry = menu; |
140 | menu_set_type(sym->type); | 152 | menu_set_type(sym->type); |
141 | break; | 153 | break; |
142 | } | 154 | } |
143 | } | 155 | } |
144 | parentdep = expr_alloc_symbol(sym); | 156 | parentdep = expr_alloc_symbol(sym); |
145 | } else if (parent->prompt) | 157 | } else if (parent->prompt) |
146 | parentdep = E_EXPR(parent->prompt->visible); | 158 | parentdep = parent->prompt->visible.expr; |
147 | else | 159 | else |
148 | parentdep = parent->dep; | 160 | parentdep = parent->dep; |
149 | 161 | ||
150 | for (menu = parent->list; menu; menu = menu->next) { | 162 | for (menu = parent->list; menu; menu = menu->next) { |
151 | basedep = expr_transform(menu->dep); | 163 | basedep = expr_transform(menu->dep); |
152 | basedep = expr_alloc_and(expr_copy(parentdep), basedep); | 164 | basedep = expr_alloc_and(expr_copy(parentdep), basedep); |
153 | basedep = expr_eliminate_dups(basedep); | 165 | basedep = expr_eliminate_dups(basedep); |
154 | menu->dep = basedep; | 166 | menu->dep = basedep; |
155 | if (menu->sym) | 167 | if (menu->sym) |
156 | prop = menu->sym->prop; | 168 | prop = menu->sym->prop; |
157 | else | 169 | else |
158 | prop = menu->prompt; | 170 | prop = menu->prompt; |
159 | for (; prop; prop = prop->next) { | 171 | for (; prop; prop = prop->next) { |
160 | if (prop->menu != menu) | 172 | if (prop->menu != menu) |
161 | continue; | 173 | continue; |
162 | dep = expr_transform(E_EXPR(prop->visible)); | 174 | dep = expr_transform(prop->visible.expr); |
163 | dep = expr_alloc_and(expr_copy(basedep), dep); | 175 | dep = expr_alloc_and(expr_copy(basedep), dep); |
164 | dep = expr_eliminate_dups(dep); | 176 | dep = expr_eliminate_dups(dep); |
165 | if (menu->sym && menu->sym->type != S_TRISTATE) | 177 | if (menu->sym && menu->sym->type != S_TRISTATE) |
166 | dep = expr_trans_bool(dep); | 178 | dep = expr_trans_bool(dep); |
167 | E_EXPR(prop->visible) = dep; | 179 | prop->visible.expr = dep; |
180 | if (prop->type == P_SELECT) { | ||
181 | struct symbol *es = prop_get_symbol(prop); | ||
182 | es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr, | ||
183 | expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep))); | ||
184 | } | ||
168 | } | 185 | } |
169 | } | 186 | } |
170 | for (menu = parent->list; menu; menu = menu->next) | 187 | for (menu = parent->list; menu; menu = menu->next) |
171 | menu_finalize(menu); | 188 | menu_finalize(menu); |
172 | } else if (sym && parent->prompt) { | 189 | } else if (sym) { |
173 | basedep = E_EXPR(parent->prompt->visible); | 190 | basedep = parent->prompt ? parent->prompt->visible.expr : NULL; |
174 | basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no); | 191 | basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no); |
175 | basedep = expr_eliminate_dups(expr_transform(basedep)); | 192 | basedep = expr_eliminate_dups(expr_transform(basedep)); |
176 | last_menu = NULL; | 193 | last_menu = NULL; |
177 | for (menu = parent->next; menu; menu = menu->next) { | 194 | for (menu = parent->next; menu; menu = menu->next) { |
178 | dep = menu->prompt ? E_EXPR(menu->prompt->visible) : menu->dep; | 195 | dep = menu->prompt ? menu->prompt->visible.expr : menu->dep; |
179 | if (!expr_contains_symbol(dep, sym)) | 196 | if (!expr_contains_symbol(dep, sym)) |
180 | break; | 197 | break; |
181 | if (expr_depends_symbol(dep, sym)) | 198 | if (expr_depends_symbol(dep, sym)) |
182 | goto next; | 199 | goto next; |
183 | dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no); | 200 | dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no); |
184 | dep = expr_eliminate_dups(expr_transform(dep)); | 201 | dep = expr_eliminate_dups(expr_transform(dep)); |
185 | dep2 = expr_copy(basedep); | 202 | dep2 = expr_copy(basedep); |
186 | expr_eliminate_eq(&dep, &dep2); | 203 | expr_eliminate_eq(&dep, &dep2); |
@@ -199,50 +216,122 @@ void menu_finalize(struct menu *parent) | |||
199 | parent->list = parent->next; | 216 | parent->list = parent->next; |
200 | parent->next = last_menu->next; | 217 | parent->next = last_menu->next; |
201 | last_menu->next = NULL; | 218 | last_menu->next = NULL; |
202 | } | 219 | } |
203 | } | 220 | } |
204 | for (menu = parent->list; menu; menu = menu->next) { | 221 | for (menu = parent->list; menu; menu = menu->next) { |
205 | if (sym && sym_is_choice(sym) && menu->sym) { | 222 | if (sym && sym_is_choice(sym) && menu->sym) { |
206 | menu->sym->flags |= SYMBOL_CHOICEVAL; | 223 | menu->sym->flags |= SYMBOL_CHOICEVAL; |
224 | if (!menu->prompt) | ||
225 | fprintf(stderr, "%s:%d:warning: choice value must have a prompt\n", | ||
226 | menu->file->name, menu->lineno); | ||
227 | for (prop = menu->sym->prop; prop; prop = prop->next) { | ||
228 | if (prop->type == P_PROMPT && prop->menu != menu) { | ||
229 | fprintf(stderr, "%s:%d:warning: choice values currently only support a single prompt\n", | ||
230 | prop->file->name, prop->lineno); | ||
231 | |||
232 | } | ||
233 | if (prop->type == P_DEFAULT) | ||
234 | fprintf(stderr, "%s:%d:warning: defaults for choice values not supported\n", | ||
235 | prop->file->name, prop->lineno); | ||
236 | } | ||
207 | current_entry = menu; | 237 | current_entry = menu; |
208 | menu_set_type(sym->type); | 238 | menu_set_type(sym->type); |
209 | menu_add_prop(P_CHOICE, NULL, parent->sym, NULL); | 239 | menu_add_symbol(P_CHOICE, sym, NULL); |
210 | prop = sym_get_choice_prop(parent->sym); | 240 | prop = sym_get_choice_prop(sym); |
211 | //dep = expr_alloc_one(E_CHOICE, dep); | 241 | for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr) |
212 | //dep->right.sym = menu->sym; | 242 | ; |
213 | prop->dep = expr_alloc_one(E_CHOICE, prop->dep); | 243 | *ep = expr_alloc_one(E_CHOICE, NULL); |
214 | prop->dep->right.sym = menu->sym; | 244 | (*ep)->right.sym = menu->sym; |
215 | } | 245 | } |
216 | if (menu->list && (!menu->prompt || !menu->prompt->text)) { | 246 | if (menu->list && (!menu->prompt || !menu->prompt->text)) { |
217 | for (last_menu = menu->list; ; last_menu = last_menu->next) { | 247 | for (last_menu = menu->list; ; last_menu = last_menu->next) { |
218 | last_menu->parent = parent; | 248 | last_menu->parent = parent; |
219 | if (!last_menu->next) | 249 | if (!last_menu->next) |
220 | break; | 250 | break; |
221 | } | 251 | } |
222 | last_menu->next = menu->next; | 252 | last_menu->next = menu->next; |
223 | menu->next = menu->list; | 253 | menu->next = menu->list; |
224 | menu->list = NULL; | 254 | menu->list = NULL; |
225 | } | 255 | } |
226 | } | 256 | } |
257 | |||
258 | if (sym && !(sym->flags & SYMBOL_WARNED)) { | ||
259 | struct symbol *sym2; | ||
260 | if (sym->type == S_UNKNOWN) | ||
261 | fprintf(stderr, "%s:%d:warning: config symbol defined without type\n", | ||
262 | parent->file->name, parent->lineno); | ||
263 | |||
264 | if (sym_is_choice(sym) && !parent->prompt) | ||
265 | fprintf(stderr, "%s:%d:warning: choice must have a prompt\n", | ||
266 | parent->file->name, parent->lineno); | ||
267 | |||
268 | for (prop = sym->prop; prop; prop = prop->next) { | ||
269 | switch (prop->type) { | ||
270 | case P_DEFAULT: | ||
271 | if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) && | ||
272 | prop->expr->type != E_SYMBOL) | ||
273 | fprintf(stderr, "%s:%d:warning: default must be a single symbol\n", | ||
274 | prop->file->name, prop->lineno); | ||
275 | break; | ||
276 | case P_SELECT: | ||
277 | sym2 = prop_get_symbol(prop); | ||
278 | if ((sym->type != S_BOOLEAN && sym->type != S_TRISTATE) || | ||
279 | (sym2->type != S_BOOLEAN && sym2->type != S_TRISTATE)) | ||
280 | fprintf(stderr, "%s:%d:warning: enable is only allowed with boolean and tristate symbols\n", | ||
281 | prop->file->name, prop->lineno); | ||
282 | break; | ||
283 | case P_RANGE: | ||
284 | if (sym->type != S_INT && sym->type != S_HEX) | ||
285 | fprintf(stderr, "%s:%d:warning: range is only allowed for int or hex symbols\n", | ||
286 | prop->file->name, prop->lineno); | ||
287 | if (!sym_string_valid(sym, prop->expr->left.sym->name) || | ||
288 | !sym_string_valid(sym, prop->expr->right.sym->name)) | ||
289 | fprintf(stderr, "%s:%d:warning: range is invalid\n", | ||
290 | prop->file->name, prop->lineno); | ||
291 | break; | ||
292 | default: | ||
293 | ; | ||
294 | } | ||
295 | } | ||
296 | sym->flags |= SYMBOL_WARNED; | ||
297 | } | ||
298 | |||
299 | if (sym && !sym_is_optional(sym) && parent->prompt) { | ||
300 | sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr, | ||
301 | expr_alloc_and(parent->prompt->visible.expr, | ||
302 | expr_alloc_symbol(&symbol_mod))); | ||
303 | } | ||
227 | } | 304 | } |
228 | 305 | ||
229 | bool menu_is_visible(struct menu *menu) | 306 | bool menu_is_visible(struct menu *menu) |
230 | { | 307 | { |
308 | struct menu *child; | ||
309 | struct symbol *sym; | ||
231 | tristate visible; | 310 | tristate visible; |
232 | 311 | ||
233 | if (!menu->prompt) | 312 | if (!menu->prompt) |
234 | return false; | 313 | return false; |
235 | if (menu->sym) { | 314 | sym = menu->sym; |
236 | sym_calc_value(menu->sym); | 315 | if (sym) { |
237 | visible = E_TRI(menu->prompt->visible); | 316 | sym_calc_value(sym); |
317 | visible = menu->prompt->visible.tri; | ||
238 | } else | 318 | } else |
239 | visible = E_CALC(menu->prompt->visible); | 319 | visible = menu->prompt->visible.tri = expr_calc_value(menu->prompt->visible.expr); |
240 | return visible != no; | 320 | |
321 | if (visible != no) | ||
322 | return true; | ||
323 | if (!sym || sym_get_tristate_value(menu->sym) == no) | ||
324 | return false; | ||
325 | |||
326 | for (child = menu->list; child; child = child->next) | ||
327 | if (menu_is_visible(child)) | ||
328 | return true; | ||
329 | return false; | ||
241 | } | 330 | } |
242 | 331 | ||
243 | const char *menu_get_prompt(struct menu *menu) | 332 | const char *menu_get_prompt(struct menu *menu) |
244 | { | 333 | { |
245 | if (menu->prompt) | 334 | if (menu->prompt) |
246 | return menu->prompt->text; | 335 | return menu->prompt->text; |
247 | else if (menu->sym) | 336 | else if (menu->sym) |
248 | return menu->sym->name; | 337 | return menu->sym->name; |
@@ -253,20 +342,19 @@ struct menu *menu_get_root_menu(struct menu *menu) | |||
253 | { | 342 | { |
254 | return &rootmenu; | 343 | return &rootmenu; |
255 | } | 344 | } |
256 | 345 | ||
257 | struct menu *menu_get_parent_menu(struct menu *menu) | 346 | struct menu *menu_get_parent_menu(struct menu *menu) |
258 | { | 347 | { |
259 | enum prop_type type; | 348 | enum prop_type type; |
260 | 349 | ||
261 | while (menu != &rootmenu) { | 350 | for (; menu != &rootmenu; menu = menu->parent) { |
262 | menu = menu->parent; | ||
263 | type = menu->prompt ? menu->prompt->type : 0; | 351 | type = menu->prompt ? menu->prompt->type : 0; |
264 | if (type == P_MENU || type == P_ROOTMENU) | 352 | if (type == P_MENU) |
265 | break; | 353 | break; |
266 | } | 354 | } |
267 | return menu; | 355 | return menu; |
268 | } | 356 | } |
269 | 357 | ||
270 | struct file *file_lookup(const char *name) | 358 | struct file *file_lookup(const char *name) |
271 | { | 359 | { |
272 | struct file *file; | 360 | struct file *file; |