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