This source file includes following definitions.
- menu_warn
- prop_warn
- _menu_init
- menu_add_entry
- menu_add_menu
- menu_end_menu
- rewrite_m
- menu_add_dep
- menu_set_type
- menu_add_prop
- menu_add_prompt
- menu_add_visibility
- menu_add_expr
- menu_add_symbol
- menu_add_option_modules
- menu_add_option_defconfig_list
- menu_add_option_allnoconfig_y
- menu_validate_number
- sym_check_prop
- menu_finalize
- menu_has_prompt
- menu_is_empty
- menu_is_visible
- menu_get_prompt
- menu_get_root_menu
- menu_get_parent_menu
- menu_has_help
- menu_get_help
- get_prompt_str
- get_symbol_prop
- get_symbol_props_str
- get_symbol_str
- get_relations_str
- menu_get_ext_help
1
2
3
4
5
6 #include <ctype.h>
7 #include <stdarg.h>
8 #include <stdlib.h>
9 #include <string.h>
10
11 #include "lkc.h"
12
13 static const char nohelp_text[] = "There is no help available for this option.";
14
15 struct menu rootmenu;
16 static struct menu **last_entry_ptr;
17
18 struct file *file_list;
19 struct file *current_file;
20
21 void menu_warn(struct menu *menu, const char *fmt, ...)
22 {
23 va_list ap;
24 va_start(ap, fmt);
25 fprintf(stderr, "%s:%d:warning: ", menu->file->name, menu->lineno);
26 vfprintf(stderr, fmt, ap);
27 fprintf(stderr, "\n");
28 va_end(ap);
29 }
30
31 static void prop_warn(struct property *prop, const char *fmt, ...)
32 {
33 va_list ap;
34 va_start(ap, fmt);
35 fprintf(stderr, "%s:%d:warning: ", prop->file->name, prop->lineno);
36 vfprintf(stderr, fmt, ap);
37 fprintf(stderr, "\n");
38 va_end(ap);
39 }
40
41 void _menu_init(void)
42 {
43 current_entry = current_menu = &rootmenu;
44 last_entry_ptr = &rootmenu.list;
45 }
46
47 void menu_add_entry(struct symbol *sym)
48 {
49 struct menu *menu;
50
51 menu = xmalloc(sizeof(*menu));
52 memset(menu, 0, sizeof(*menu));
53 menu->sym = sym;
54 menu->parent = current_menu;
55 menu->file = current_file;
56 menu->lineno = zconf_lineno();
57
58 *last_entry_ptr = menu;
59 last_entry_ptr = &menu->next;
60 current_entry = menu;
61 if (sym)
62 menu_add_symbol(P_SYMBOL, sym, NULL);
63 }
64
65 struct menu *menu_add_menu(void)
66 {
67 last_entry_ptr = ¤t_entry->list;
68 return current_menu = current_entry;
69 }
70
71 void menu_end_menu(void)
72 {
73 last_entry_ptr = ¤t_menu->next;
74 current_menu = current_menu->parent;
75 }
76
77
78
79
80
81 static struct expr *rewrite_m(struct expr *e)
82 {
83 if (!e)
84 return e;
85
86 switch (e->type) {
87 case E_NOT:
88 e->left.expr = rewrite_m(e->left.expr);
89 break;
90 case E_OR:
91 case E_AND:
92 e->left.expr = rewrite_m(e->left.expr);
93 e->right.expr = rewrite_m(e->right.expr);
94 break;
95 case E_SYMBOL:
96
97 if (e->left.sym == &symbol_mod)
98 return expr_alloc_and(e, expr_alloc_symbol(modules_sym));
99 break;
100 default:
101 break;
102 }
103 return e;
104 }
105
106 void menu_add_dep(struct expr *dep)
107 {
108 current_entry->dep = expr_alloc_and(current_entry->dep, dep);
109 }
110
111 void menu_set_type(int type)
112 {
113 struct symbol *sym = current_entry->sym;
114
115 if (sym->type == type)
116 return;
117 if (sym->type == S_UNKNOWN) {
118 sym->type = type;
119 return;
120 }
121 menu_warn(current_entry,
122 "ignoring type redefinition of '%s' from '%s' to '%s'",
123 sym->name ? sym->name : "<choice>",
124 sym_type_name(sym->type), sym_type_name(type));
125 }
126
127 static struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep)
128 {
129 struct property *prop = prop_alloc(type, current_entry->sym);
130
131 prop->menu = current_entry;
132 prop->expr = expr;
133 prop->visible.expr = dep;
134
135 if (prompt) {
136 if (isspace(*prompt)) {
137 prop_warn(prop, "leading whitespace ignored");
138 while (isspace(*prompt))
139 prompt++;
140 }
141 if (current_entry->prompt && current_entry != &rootmenu)
142 prop_warn(prop, "prompt redefined");
143
144
145 if(type == P_PROMPT) {
146 struct menu *menu = current_entry;
147
148 while ((menu = menu->parent) != NULL) {
149 struct expr *dup_expr;
150
151 if (!menu->visibility)
152 continue;
153
154
155
156
157
158
159
160
161
162 dup_expr = expr_copy(menu->visibility);
163
164 prop->visible.expr
165 = expr_alloc_and(prop->visible.expr,
166 dup_expr);
167 }
168 }
169
170 current_entry->prompt = prop;
171 }
172 prop->text = prompt;
173
174 return prop;
175 }
176
177 struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep)
178 {
179 return menu_add_prop(type, prompt, NULL, dep);
180 }
181
182 void menu_add_visibility(struct expr *expr)
183 {
184 current_entry->visibility = expr_alloc_and(current_entry->visibility,
185 expr);
186 }
187
188 void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep)
189 {
190 menu_add_prop(type, NULL, expr, dep);
191 }
192
193 void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep)
194 {
195 menu_add_prop(type, NULL, expr_alloc_symbol(sym), dep);
196 }
197
198 void menu_add_option_modules(void)
199 {
200 if (modules_sym)
201 zconf_error("symbol '%s' redefines option 'modules' already defined by symbol '%s'",
202 current_entry->sym->name, modules_sym->name);
203 modules_sym = current_entry->sym;
204 }
205
206 void menu_add_option_defconfig_list(void)
207 {
208 if (!sym_defconfig_list)
209 sym_defconfig_list = current_entry->sym;
210 else if (sym_defconfig_list != current_entry->sym)
211 zconf_error("trying to redefine defconfig symbol");
212 sym_defconfig_list->flags |= SYMBOL_NO_WRITE;
213 }
214
215 void menu_add_option_allnoconfig_y(void)
216 {
217 current_entry->sym->flags |= SYMBOL_ALLNOCONFIG_Y;
218 }
219
220 static int menu_validate_number(struct symbol *sym, struct symbol *sym2)
221 {
222 return sym2->type == S_INT || sym2->type == S_HEX ||
223 (sym2->type == S_UNKNOWN && sym_string_valid(sym, sym2->name));
224 }
225
226 static void sym_check_prop(struct symbol *sym)
227 {
228 struct property *prop;
229 struct symbol *sym2;
230 char *use;
231
232 for (prop = sym->prop; prop; prop = prop->next) {
233 switch (prop->type) {
234 case P_DEFAULT:
235 if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) &&
236 prop->expr->type != E_SYMBOL)
237 prop_warn(prop,
238 "default for config symbol '%s'"
239 " must be a single symbol", sym->name);
240 if (prop->expr->type != E_SYMBOL)
241 break;
242 sym2 = prop_get_symbol(prop);
243 if (sym->type == S_HEX || sym->type == S_INT) {
244 if (!menu_validate_number(sym, sym2))
245 prop_warn(prop,
246 "'%s': number is invalid",
247 sym->name);
248 }
249 if (sym_is_choice(sym)) {
250 struct property *choice_prop =
251 sym_get_choice_prop(sym2);
252
253 if (!choice_prop ||
254 prop_get_symbol(choice_prop) != sym)
255 prop_warn(prop,
256 "choice default symbol '%s' is not contained in the choice",
257 sym2->name);
258 }
259 break;
260 case P_SELECT:
261 case P_IMPLY:
262 use = prop->type == P_SELECT ? "select" : "imply";
263 sym2 = prop_get_symbol(prop);
264 if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE)
265 prop_warn(prop,
266 "config symbol '%s' uses %s, but is "
267 "not bool or tristate", sym->name, use);
268 else if (sym2->type != S_UNKNOWN &&
269 sym2->type != S_BOOLEAN &&
270 sym2->type != S_TRISTATE)
271 prop_warn(prop,
272 "'%s' has wrong type. '%s' only "
273 "accept arguments of bool and "
274 "tristate type", sym2->name, use);
275 break;
276 case P_RANGE:
277 if (sym->type != S_INT && sym->type != S_HEX)
278 prop_warn(prop, "range is only allowed "
279 "for int or hex symbols");
280 if (!menu_validate_number(sym, prop->expr->left.sym) ||
281 !menu_validate_number(sym, prop->expr->right.sym))
282 prop_warn(prop, "range is invalid");
283 break;
284 default:
285 ;
286 }
287 }
288 }
289
290 void menu_finalize(struct menu *parent)
291 {
292 struct menu *menu, *last_menu;
293 struct symbol *sym;
294 struct property *prop;
295 struct expr *parentdep, *basedep, *dep, *dep2, **ep;
296
297 sym = parent->sym;
298 if (parent->list) {
299
300
301
302
303
304 if (sym && sym_is_choice(sym)) {
305 if (sym->type == S_UNKNOWN) {
306
307 current_entry = parent;
308 for (menu = parent->list; menu; menu = menu->next) {
309 if (menu->sym && menu->sym->type != S_UNKNOWN) {
310 menu_set_type(menu->sym->type);
311 break;
312 }
313 }
314 }
315
316 for (menu = parent->list; menu; menu = menu->next) {
317 current_entry = menu;
318 if (menu->sym && menu->sym->type == S_UNKNOWN)
319 menu_set_type(sym->type);
320 }
321
322
323
324
325
326
327
328 parentdep = expr_alloc_symbol(sym);
329 } else if (parent->prompt)
330
331 parentdep = parent->prompt->visible.expr;
332 else
333
334 parentdep = parent->dep;
335
336
337 for (menu = parent->list; menu; menu = menu->next) {
338
339
340
341
342 basedep = rewrite_m(menu->dep);
343 basedep = expr_transform(basedep);
344 basedep = expr_alloc_and(expr_copy(parentdep), basedep);
345 basedep = expr_eliminate_dups(basedep);
346 menu->dep = basedep;
347
348 if (menu->sym)
349
350
351
352
353 prop = menu->sym->prop;
354 else
355
356
357
358
359 prop = menu->prompt;
360
361
362 for (; prop; prop = prop->next) {
363 if (prop->menu != menu)
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379 continue;
380
381
382
383
384
385
386 dep = rewrite_m(prop->visible.expr);
387 dep = expr_transform(dep);
388 dep = expr_alloc_and(expr_copy(basedep), dep);
389 dep = expr_eliminate_dups(dep);
390 if (menu->sym && menu->sym->type != S_TRISTATE)
391 dep = expr_trans_bool(dep);
392 prop->visible.expr = dep;
393
394
395
396
397
398 if (prop->type == P_SELECT) {
399 struct symbol *es = prop_get_symbol(prop);
400 es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr,
401 expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep)));
402 } else if (prop->type == P_IMPLY) {
403 struct symbol *es = prop_get_symbol(prop);
404 es->implied.expr = expr_alloc_or(es->implied.expr,
405 expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep)));
406 }
407 }
408 }
409
410 if (sym && sym_is_choice(sym))
411 expr_free(parentdep);
412
413
414
415
416
417 for (menu = parent->list; menu; menu = menu->next)
418 menu_finalize(menu);
419 } else if (sym) {
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442 basedep = parent->prompt ? parent->prompt->visible.expr : NULL;
443 basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no);
444 basedep = expr_eliminate_dups(expr_transform(basedep));
445
446
447 last_menu = NULL;
448 for (menu = parent->next; menu; menu = menu->next) {
449 dep = menu->prompt ? menu->prompt->visible.expr : menu->dep;
450 if (!expr_contains_symbol(dep, sym))
451
452 break;
453 if (expr_depends_symbol(dep, sym))
454
455 goto next;
456
457
458
459
460
461
462
463
464
465
466 dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no);
467 dep = expr_eliminate_dups(expr_transform(dep));
468 dep2 = expr_copy(basedep);
469 expr_eliminate_eq(&dep, &dep2);
470 expr_free(dep);
471 if (!expr_is_yes(dep2)) {
472
473 expr_free(dep2);
474 break;
475 }
476
477 expr_free(dep2);
478 next:
479 menu_finalize(menu);
480 menu->parent = parent;
481 last_menu = menu;
482 }
483 expr_free(basedep);
484 if (last_menu) {
485 parent->list = parent->next;
486 parent->next = last_menu->next;
487 last_menu->next = NULL;
488 }
489
490 sym->dir_dep.expr = expr_alloc_or(sym->dir_dep.expr, parent->dep);
491 }
492 for (menu = parent->list; menu; menu = menu->next) {
493 if (sym && sym_is_choice(sym) &&
494 menu->sym && !sym_is_choice_value(menu->sym)) {
495 current_entry = menu;
496 menu->sym->flags |= SYMBOL_CHOICEVAL;
497 if (!menu->prompt)
498 menu_warn(menu, "choice value must have a prompt");
499 for (prop = menu->sym->prop; prop; prop = prop->next) {
500 if (prop->type == P_DEFAULT)
501 prop_warn(prop, "defaults for choice "
502 "values not supported");
503 if (prop->menu == menu)
504 continue;
505 if (prop->type == P_PROMPT &&
506 prop->menu->parent->sym != sym)
507 prop_warn(prop, "choice value used outside its choice group");
508 }
509
510
511
512
513
514
515 if (sym->type == S_TRISTATE && menu->sym->type != S_TRISTATE) {
516 basedep = expr_alloc_comp(E_EQUAL, sym, &symbol_yes);
517 menu->dep = expr_alloc_and(basedep, menu->dep);
518 for (prop = menu->sym->prop; prop; prop = prop->next) {
519 if (prop->menu != menu)
520 continue;
521 prop->visible.expr = expr_alloc_and(expr_copy(basedep),
522 prop->visible.expr);
523 }
524 }
525 menu_add_symbol(P_CHOICE, sym, NULL);
526 prop = sym_get_choice_prop(sym);
527 for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr)
528 ;
529 *ep = expr_alloc_one(E_LIST, NULL);
530 (*ep)->right.sym = menu->sym;
531 }
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561 if (menu->list && (!menu->prompt || !menu->prompt->text)) {
562 for (last_menu = menu->list; ; last_menu = last_menu->next) {
563 last_menu->parent = parent;
564 if (!last_menu->next)
565 break;
566 }
567 last_menu->next = menu->next;
568 menu->next = menu->list;
569 menu->list = NULL;
570 }
571 }
572
573 if (sym && !(sym->flags & SYMBOL_WARNED)) {
574 if (sym->type == S_UNKNOWN)
575 menu_warn(parent, "config symbol defined without type");
576
577 if (sym_is_choice(sym) && !parent->prompt)
578 menu_warn(parent, "choice must have a prompt");
579
580
581 sym_check_prop(sym);
582 sym->flags |= SYMBOL_WARNED;
583 }
584
585
586
587
588
589
590
591
592
593
594 if (sym && !sym_is_optional(sym) && parent->prompt) {
595 sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr,
596 expr_alloc_and(parent->prompt->visible.expr,
597 expr_alloc_symbol(&symbol_mod)));
598 }
599 }
600
601 bool menu_has_prompt(struct menu *menu)
602 {
603 if (!menu->prompt)
604 return false;
605 return true;
606 }
607
608
609
610
611
612
613 bool menu_is_empty(struct menu *menu)
614 {
615 struct menu *child;
616
617 for (child = menu->list; child; child = child->next) {
618 if (menu_is_visible(child))
619 return(false);
620 }
621 return(true);
622 }
623
624 bool menu_is_visible(struct menu *menu)
625 {
626 struct menu *child;
627 struct symbol *sym;
628 tristate visible;
629
630 if (!menu->prompt)
631 return false;
632
633 if (menu->visibility) {
634 if (expr_calc_value(menu->visibility) == no)
635 return false;
636 }
637
638 sym = menu->sym;
639 if (sym) {
640 sym_calc_value(sym);
641 visible = menu->prompt->visible.tri;
642 } else
643 visible = menu->prompt->visible.tri = expr_calc_value(menu->prompt->visible.expr);
644
645 if (visible != no)
646 return true;
647
648 if (!sym || sym_get_tristate_value(menu->sym) == no)
649 return false;
650
651 for (child = menu->list; child; child = child->next) {
652 if (menu_is_visible(child)) {
653 if (sym)
654 sym->flags |= SYMBOL_DEF_USER;
655 return true;
656 }
657 }
658
659 return false;
660 }
661
662 const char *menu_get_prompt(struct menu *menu)
663 {
664 if (menu->prompt)
665 return menu->prompt->text;
666 else if (menu->sym)
667 return menu->sym->name;
668 return NULL;
669 }
670
671 struct menu *menu_get_root_menu(struct menu *menu)
672 {
673 return &rootmenu;
674 }
675
676 struct menu *menu_get_parent_menu(struct menu *menu)
677 {
678 enum prop_type type;
679
680 for (; menu != &rootmenu; menu = menu->parent) {
681 type = menu->prompt ? menu->prompt->type : 0;
682 if (type == P_MENU)
683 break;
684 }
685 return menu;
686 }
687
688 bool menu_has_help(struct menu *menu)
689 {
690 return menu->help != NULL;
691 }
692
693 const char *menu_get_help(struct menu *menu)
694 {
695 if (menu->help)
696 return menu->help;
697 else
698 return "";
699 }
700
701 static void get_prompt_str(struct gstr *r, struct property *prop,
702 struct list_head *head)
703 {
704 int i, j;
705 struct menu *submenu[8], *menu, *location = NULL;
706 struct jump_key *jump = NULL;
707
708 str_printf(r, "Prompt: %s\n", prop->text);
709 menu = prop->menu->parent;
710 for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent) {
711 bool accessible = menu_is_visible(menu);
712
713 submenu[i++] = menu;
714 if (location == NULL && accessible)
715 location = menu;
716 }
717 if (head && location) {
718 jump = xmalloc(sizeof(struct jump_key));
719
720 if (menu_is_visible(prop->menu)) {
721
722
723
724
725
726
727 jump->target = prop->menu;
728 } else
729 jump->target = location;
730
731 if (list_empty(head))
732 jump->index = 0;
733 else
734 jump->index = list_entry(head->prev, struct jump_key,
735 entries)->index + 1;
736
737 list_add_tail(&jump->entries, head);
738 }
739
740 if (i > 0) {
741 str_printf(r, " Location:\n");
742 for (j = 4; --i >= 0; j += 2) {
743 menu = submenu[i];
744 if (jump && menu == location)
745 jump->offset = strlen(r->s);
746 str_printf(r, "%*c-> %s", j, ' ',
747 menu_get_prompt(menu));
748 if (menu->sym) {
749 str_printf(r, " (%s [=%s])", menu->sym->name ?
750 menu->sym->name : "<choice>",
751 sym_get_string_value(menu->sym));
752 }
753 str_append(r, "\n");
754 }
755 }
756 }
757
758
759
760
761 static struct property *get_symbol_prop(struct symbol *sym)
762 {
763 struct property *prop = NULL;
764
765 for_all_properties(sym, prop, P_SYMBOL)
766 break;
767 return prop;
768 }
769
770 static void get_symbol_props_str(struct gstr *r, struct symbol *sym,
771 enum prop_type tok, const char *prefix)
772 {
773 bool hit = false;
774 struct property *prop;
775
776 for_all_properties(sym, prop, tok) {
777 if (!hit) {
778 str_append(r, prefix);
779 hit = true;
780 } else
781 str_printf(r, " && ");
782 expr_gstr_print(prop->expr, r);
783 }
784 if (hit)
785 str_append(r, "\n");
786 }
787
788
789
790
791 static void get_symbol_str(struct gstr *r, struct symbol *sym,
792 struct list_head *head)
793 {
794 struct property *prop;
795
796 if (sym && sym->name) {
797 str_printf(r, "Symbol: %s [=%s]\n", sym->name,
798 sym_get_string_value(sym));
799 str_printf(r, "Type : %s\n", sym_type_name(sym->type));
800 if (sym->type == S_INT || sym->type == S_HEX) {
801 prop = sym_get_range_prop(sym);
802 if (prop) {
803 str_printf(r, "Range : ");
804 expr_gstr_print(prop->expr, r);
805 str_append(r, "\n");
806 }
807 }
808 }
809 for_all_prompts(sym, prop)
810 get_prompt_str(r, prop, head);
811
812 prop = get_symbol_prop(sym);
813 if (prop) {
814 str_printf(r, " Defined at %s:%d\n", prop->menu->file->name,
815 prop->menu->lineno);
816 if (!expr_is_yes(prop->visible.expr)) {
817 str_append(r, " Depends on: ");
818 expr_gstr_print(prop->visible.expr, r);
819 str_append(r, "\n");
820 }
821 }
822
823 get_symbol_props_str(r, sym, P_SELECT, " Selects: ");
824 if (sym->rev_dep.expr) {
825 expr_gstr_print_revdep(sym->rev_dep.expr, r, yes, " Selected by [y]:\n");
826 expr_gstr_print_revdep(sym->rev_dep.expr, r, mod, " Selected by [m]:\n");
827 expr_gstr_print_revdep(sym->rev_dep.expr, r, no, " Selected by [n]:\n");
828 }
829
830 get_symbol_props_str(r, sym, P_IMPLY, " Implies: ");
831 if (sym->implied.expr) {
832 expr_gstr_print_revdep(sym->implied.expr, r, yes, " Implied by [y]:\n");
833 expr_gstr_print_revdep(sym->implied.expr, r, mod, " Implied by [m]:\n");
834 expr_gstr_print_revdep(sym->implied.expr, r, no, " Implied by [n]:\n");
835 }
836
837 str_append(r, "\n\n");
838 }
839
840 struct gstr get_relations_str(struct symbol **sym_arr, struct list_head *head)
841 {
842 struct symbol *sym;
843 struct gstr res = str_new();
844 int i;
845
846 for (i = 0; sym_arr && (sym = sym_arr[i]); i++)
847 get_symbol_str(&res, sym, head);
848 if (!i)
849 str_append(&res, "No matches found.\n");
850 return res;
851 }
852
853
854 void menu_get_ext_help(struct menu *menu, struct gstr *help)
855 {
856 struct symbol *sym = menu->sym;
857 const char *help_text = nohelp_text;
858
859 if (menu_has_help(menu)) {
860 if (sym->name)
861 str_printf(help, "%s%s:\n\n", CONFIG_, sym->name);
862 help_text = menu_get_help(menu);
863 }
864 str_printf(help, "%s\n", help_text);
865 if (sym)
866 get_symbol_str(help, sym, NULL);
867 }