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