~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/scripts/kconfig/menu.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 /*
  3  * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
  4  */
  5 
  6 #include <ctype.h>
  7 #include <stdarg.h>
  8 #include <stdlib.h>
  9 #include <string.h>
 10 
 11 #include <list.h>
 12 #include "lkc.h"
 13 #include "internal.h"
 14 
 15 static const char nohelp_text[] = "There is no help available for this option.";
 16 
 17 struct menu rootmenu;
 18 static struct menu **last_entry_ptr;
 19 
 20 /**
 21  * menu_next - return the next menu entry with depth-first traversal
 22  * @menu: pointer to the current menu
 23  * @root: root of the sub-tree to traverse. If NULL is given, the traveral
 24  *        continues until it reaches the end of the entire menu tree.
 25  * return: the menu to visit next, or NULL when it reaches the end.
 26  */
 27 struct menu *menu_next(struct menu *menu, struct menu *root)
 28 {
 29         if (menu->list)
 30                 return menu->list;
 31 
 32         while (menu != root && !menu->next)
 33                 menu = menu->parent;
 34 
 35         if (menu == root)
 36                 return NULL;
 37 
 38         return menu->next;
 39 }
 40 
 41 void menu_warn(const struct menu *menu, const char *fmt, ...)
 42 {
 43         va_list ap;
 44         va_start(ap, fmt);
 45         fprintf(stderr, "%s:%d:warning: ", menu->filename, menu->lineno);
 46         vfprintf(stderr, fmt, ap);
 47         fprintf(stderr, "\n");
 48         va_end(ap);
 49 }
 50 
 51 static void prop_warn(const struct property *prop, const char *fmt, ...)
 52 {
 53         va_list ap;
 54         va_start(ap, fmt);
 55         fprintf(stderr, "%s:%d:warning: ", prop->filename, prop->lineno);
 56         vfprintf(stderr, fmt, ap);
 57         fprintf(stderr, "\n");
 58         va_end(ap);
 59 }
 60 
 61 void _menu_init(void)
 62 {
 63         current_entry = current_menu = &rootmenu;
 64         last_entry_ptr = &rootmenu.list;
 65 }
 66 
 67 void menu_add_entry(struct symbol *sym)
 68 {
 69         struct menu *menu;
 70 
 71         menu = xmalloc(sizeof(*menu));
 72         memset(menu, 0, sizeof(*menu));
 73         menu->sym = sym;
 74         menu->parent = current_menu;
 75         menu->filename = cur_filename;
 76         menu->lineno = cur_lineno;
 77 
 78         *last_entry_ptr = menu;
 79         last_entry_ptr = &menu->next;
 80         current_entry = menu;
 81         if (sym) {
 82                 menu_add_symbol(P_SYMBOL, sym, NULL);
 83                 list_add_tail(&menu->link, &sym->menus);
 84         }
 85 }
 86 
 87 struct menu *menu_add_menu(void)
 88 {
 89         last_entry_ptr = &current_entry->list;
 90         current_menu = current_entry;
 91         return current_menu;
 92 }
 93 
 94 void menu_end_menu(void)
 95 {
 96         last_entry_ptr = &current_menu->next;
 97         current_menu = current_menu->parent;
 98 }
 99 
100 /*
101  * Rewrites 'm' to 'm' && MODULES, so that it evaluates to 'n' when running
102  * without modules
103  */
104 static struct expr *rewrite_m(struct expr *e)
105 {
106         if (!e)
107                 return e;
108 
109         switch (e->type) {
110         case E_NOT:
111                 e->left.expr = rewrite_m(e->left.expr);
112                 break;
113         case E_OR:
114         case E_AND:
115                 e->left.expr = rewrite_m(e->left.expr);
116                 e->right.expr = rewrite_m(e->right.expr);
117                 break;
118         case E_SYMBOL:
119                 /* change 'm' into 'm' && MODULES */
120                 if (e->left.sym == &symbol_mod)
121                         return expr_alloc_and(e, expr_alloc_symbol(modules_sym));
122                 break;
123         default:
124                 break;
125         }
126         return e;
127 }
128 
129 void menu_add_dep(struct expr *dep)
130 {
131         current_entry->dep = expr_alloc_and(current_entry->dep, dep);
132 }
133 
134 void menu_set_type(int type)
135 {
136         struct symbol *sym = current_entry->sym;
137 
138         if (sym->type == type)
139                 return;
140         if (sym->type == S_UNKNOWN) {
141                 sym->type = type;
142                 return;
143         }
144         menu_warn(current_entry,
145                 "ignoring type redefinition of '%s' from '%s' to '%s'",
146                 sym->name ? sym->name : "<choice>",
147                 sym_type_name(sym->type), sym_type_name(type));
148 }
149 
150 static struct property *menu_add_prop(enum prop_type type, struct expr *expr,
151                                       struct expr *dep)
152 {
153         struct property *prop;
154 
155         prop = xmalloc(sizeof(*prop));
156         memset(prop, 0, sizeof(*prop));
157         prop->type = type;
158         prop->filename = cur_filename;
159         prop->lineno = cur_lineno;
160         prop->menu = current_entry;
161         prop->expr = expr;
162         prop->visible.expr = dep;
163 
164         /* append property to the prop list of symbol */
165         if (current_entry->sym) {
166                 struct property **propp;
167 
168                 for (propp = &current_entry->sym->prop;
169                      *propp;
170                      propp = &(*propp)->next)
171                         ;
172                 *propp = prop;
173         }
174 
175         return prop;
176 }
177 
178 struct property *menu_add_prompt(enum prop_type type, const char *prompt,
179                                  struct expr *dep)
180 {
181         struct property *prop = menu_add_prop(type, NULL, dep);
182 
183         if (isspace(*prompt)) {
184                 prop_warn(prop, "leading whitespace ignored");
185                 while (isspace(*prompt))
186                         prompt++;
187         }
188         if (current_entry->prompt)
189                 prop_warn(prop, "prompt redefined");
190 
191         /* Apply all upper menus' visibilities to actual prompts. */
192         if (type == P_PROMPT) {
193                 struct menu *menu = current_entry;
194 
195                 while ((menu = menu->parent) != NULL) {
196                         struct expr *dup_expr;
197 
198                         if (!menu->visibility)
199                                 continue;
200                         /*
201                          * Do not add a reference to the menu's visibility
202                          * expression but use a copy of it. Otherwise the
203                          * expression reduction functions will modify
204                          * expressions that have multiple references which
205                          * can cause unwanted side effects.
206                          */
207                         dup_expr = expr_copy(menu->visibility);
208 
209                         prop->visible.expr = expr_alloc_and(prop->visible.expr,
210                                                             dup_expr);
211                 }
212         }
213 
214         current_entry->prompt = prop;
215         prop->text = prompt;
216 
217         return prop;
218 }
219 
220 void menu_add_visibility(struct expr *expr)
221 {
222         current_entry->visibility = expr_alloc_and(current_entry->visibility,
223             expr);
224 }
225 
226 void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep)
227 {
228         menu_add_prop(type, expr, dep);
229 }
230 
231 void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep)
232 {
233         menu_add_prop(type, expr_alloc_symbol(sym), dep);
234 }
235 
236 static 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 
242 static 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 menu *choice = sym_get_choice_menu(sym2);
267 
268                                 if (!choice || choice->sym != sym)
269                                         prop_warn(prop,
270                                                   "choice default symbol '%s' is not contained in the choice",
271                                                   sym2->name);
272                         }
273                         break;
274                 case P_SELECT:
275                 case P_IMPLY:
276                         use = prop->type == P_SELECT ? "select" : "imply";
277                         sym2 = prop_get_symbol(prop);
278                         if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE)
279                                 prop_warn(prop,
280                                     "config symbol '%s' uses %s, but is "
281                                     "not bool or tristate", sym->name, use);
282                         else if (sym2->type != S_UNKNOWN &&
283                                  sym2->type != S_BOOLEAN &&
284                                  sym2->type != S_TRISTATE)
285                                 prop_warn(prop,
286                                     "'%s' has wrong type. '%s' only "
287                                     "accept arguments of bool and "
288                                     "tristate type", sym2->name, use);
289                         break;
290                 case P_RANGE:
291                         if (sym->type != S_INT && sym->type != S_HEX)
292                                 prop_warn(prop, "range is only allowed "
293                                                 "for int or hex symbols");
294                         if (!menu_validate_number(sym, prop->expr->left.sym) ||
295                             !menu_validate_number(sym, prop->expr->right.sym))
296                                 prop_warn(prop, "range is invalid");
297                         break;
298                 default:
299                         ;
300                 }
301         }
302 }
303 
304 static void _menu_finalize(struct menu *parent, bool inside_choice)
305 {
306         struct menu *menu, *last_menu;
307         struct symbol *sym;
308         struct property *prop;
309         struct expr *basedep, *dep, *dep2;
310 
311         sym = parent->sym;
312         if (parent->list) {
313                 /*
314                  * This menu node has children. We (recursively) process them
315                  * and propagate parent dependencies before moving on.
316                  */
317 
318                 /* For each child menu node... */
319                 for (menu = parent->list; menu; menu = menu->next) {
320                         /*
321                          * Propagate parent dependencies to the child menu
322                          * node, also rewriting and simplifying expressions
323                          */
324                         basedep = rewrite_m(menu->dep);
325                         basedep = expr_transform(basedep);
326                         basedep = expr_alloc_and(expr_copy(parent->dep), basedep);
327                         basedep = expr_eliminate_dups(basedep);
328                         menu->dep = basedep;
329 
330                         if (menu->sym)
331                                 /*
332                                  * Note: For symbols, all prompts are included
333                                  * too in the symbol's own property list
334                                  */
335                                 prop = menu->sym->prop;
336                         else
337                                 /*
338                                  * For non-symbol menu nodes, we just need to
339                                  * handle the prompt
340                                  */
341                                 prop = menu->prompt;
342 
343                         /* For each property... */
344                         for (; prop; prop = prop->next) {
345                                 if (prop->menu != menu)
346                                         /*
347                                          * Two possibilities:
348                                          *
349                                          * 1. The property lacks dependencies
350                                          *    and so isn't location-specific,
351                                          *    e.g. an 'option'
352                                          *
353                                          * 2. The property belongs to a symbol
354                                          *    defined in multiple locations and
355                                          *    is from some other location. It
356                                          *    will be handled there in that
357                                          *    case.
358                                          *
359                                          * Skip the property.
360                                          */
361                                         continue;
362 
363                                 /*
364                                  * Propagate parent dependencies to the
365                                  * property's condition, rewriting and
366                                  * simplifying expressions at the same time
367                                  */
368                                 dep = rewrite_m(prop->visible.expr);
369                                 dep = expr_transform(dep);
370                                 dep = expr_alloc_and(expr_copy(basedep), dep);
371                                 dep = expr_eliminate_dups(dep);
372                                 prop->visible.expr = dep;
373 
374                                 /*
375                                  * Handle selects and implies, which modify the
376                                  * dependencies of the selected/implied symbol
377                                  */
378                                 if (prop->type == P_SELECT) {
379                                         struct symbol *es = prop_get_symbol(prop);
380                                         es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr,
381                                                         expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep)));
382                                 } else if (prop->type == P_IMPLY) {
383                                         struct symbol *es = prop_get_symbol(prop);
384                                         es->implied.expr = expr_alloc_or(es->implied.expr,
385                                                         expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep)));
386                                 }
387                         }
388                 }
389 
390                 /*
391                  * Recursively process children in the same fashion before
392                  * moving on
393                  */
394                 for (menu = parent->list; menu; menu = menu->next)
395                         _menu_finalize(menu, sym && sym_is_choice(sym));
396         } else if (!inside_choice && sym) {
397                 /*
398                  * Automatic submenu creation. If sym is a symbol and A, B, C,
399                  * ... are consecutive items (symbols, menus, ifs, etc.) that
400                  * all depend on sym, then the following menu structure is
401                  * created:
402                  *
403                  *      sym
404                  *       +-A
405                  *       +-B
406                  *       +-C
407                  *       ...
408                  *
409                  * This also works recursively, giving the following structure
410                  * if A is a symbol and B depends on A:
411                  *
412                  *      sym
413                  *       +-A
414                  *       | +-B
415                  *       +-C
416                  *       ...
417                  */
418 
419                 basedep = parent->prompt ? parent->prompt->visible.expr : NULL;
420                 basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no);
421                 basedep = expr_eliminate_dups(expr_transform(basedep));
422 
423                 /* Examine consecutive elements after sym */
424                 last_menu = NULL;
425                 for (menu = parent->next; menu; menu = menu->next) {
426                         dep = menu->prompt ? menu->prompt->visible.expr : menu->dep;
427                         if (!expr_contains_symbol(dep, sym))
428                                 /* No dependency, quit */
429                                 break;
430                         if (expr_depends_symbol(dep, sym))
431                                 /* Absolute dependency, put in submenu */
432                                 goto next;
433 
434                         /*
435                          * Also consider it a dependency on sym if our
436                          * dependencies contain sym and are a "superset" of
437                          * sym's dependencies, e.g. '(sym || Q) && R' when sym
438                          * depends on R.
439                          *
440                          * Note that 'R' might be from an enclosing menu or if,
441                          * making this a more common case than it might seem.
442                          */
443                         dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no);
444                         dep = expr_eliminate_dups(expr_transform(dep));
445                         dep2 = expr_copy(basedep);
446                         expr_eliminate_eq(&dep, &dep2);
447                         expr_free(dep);
448                         if (!expr_is_yes(dep2)) {
449                                 /* Not superset, quit */
450                                 expr_free(dep2);
451                                 break;
452                         }
453                         /* Superset, put in submenu */
454                         expr_free(dep2);
455                 next:
456                         _menu_finalize(menu, false);
457                         menu->parent = parent;
458                         last_menu = menu;
459                 }
460                 expr_free(basedep);
461                 if (last_menu) {
462                         parent->list = parent->next;
463                         parent->next = last_menu->next;
464                         last_menu->next = NULL;
465                 }
466 
467                 sym->dir_dep.expr = expr_alloc_or(sym->dir_dep.expr, parent->dep);
468         }
469         for (menu = parent->list; menu; menu = menu->next) {
470                 /*
471                  * This code serves two purposes:
472                  *
473                  * (1) Flattening 'if' blocks, which do not specify a submenu
474                  *     and only add dependencies.
475                  *
476                  *     (Automatic submenu creation might still create a submenu
477                  *     from an 'if' before this code runs.)
478                  *
479                  * (2) "Undoing" any automatic submenus created earlier below
480                  *     promptless symbols.
481                  *
482                  * Before:
483                  *
484                  *      A
485                  *      if ... (or promptless symbol)
486                  *       +-B
487                  *       +-C
488                  *      D
489                  *
490                  * After:
491                  *
492                  *      A
493                  *      if ... (or promptless symbol)
494                  *      B
495                  *      C
496                  *      D
497                  */
498                 if (menu->list && (!menu->prompt || !menu->prompt->text)) {
499                         for (last_menu = menu->list; ; last_menu = last_menu->next) {
500                                 last_menu->parent = parent;
501                                 if (!last_menu->next)
502                                         break;
503                         }
504                         last_menu->next = menu->next;
505                         menu->next = menu->list;
506                         menu->list = NULL;
507                 }
508         }
509 
510         if (sym && !(sym->flags & SYMBOL_WARNED)) {
511                 if (sym->type == S_UNKNOWN)
512                         menu_warn(parent, "config symbol defined without type");
513 
514                 /* Check properties connected to this symbol */
515                 sym_check_prop(sym);
516                 sym->flags |= SYMBOL_WARNED;
517         }
518 }
519 
520 void menu_finalize(void)
521 {
522         _menu_finalize(&rootmenu, false);
523 }
524 
525 bool menu_has_prompt(const struct menu *menu)
526 {
527         if (!menu->prompt)
528                 return false;
529         return true;
530 }
531 
532 /*
533  * Determine if a menu is empty.
534  * A menu is considered empty if it contains no or only
535  * invisible entries.
536  */
537 bool menu_is_empty(struct menu *menu)
538 {
539         struct menu *child;
540 
541         for (child = menu->list; child; child = child->next) {
542                 if (menu_is_visible(child))
543                         return(false);
544         }
545         return(true);
546 }
547 
548 bool menu_is_visible(struct menu *menu)
549 {
550         struct symbol *sym;
551         tristate visible;
552 
553         if (!menu->prompt)
554                 return false;
555 
556         if (menu->visibility) {
557                 if (expr_calc_value(menu->visibility) == no)
558                         return false;
559         }
560 
561         sym = menu->sym;
562         if (sym) {
563                 sym_calc_value(sym);
564                 visible = menu->prompt->visible.tri;
565         } else
566                 visible = menu->prompt->visible.tri = expr_calc_value(menu->prompt->visible.expr);
567 
568         return visible != no;
569 }
570 
571 const char *menu_get_prompt(const struct menu *menu)
572 {
573         if (menu->prompt)
574                 return menu->prompt->text;
575         else if (menu->sym)
576                 return menu->sym->name;
577         return NULL;
578 }
579 
580 struct menu *menu_get_parent_menu(struct menu *menu)
581 {
582         enum prop_type type;
583 
584         for (; menu != &rootmenu; menu = menu->parent) {
585                 type = menu->prompt ? menu->prompt->type : 0;
586                 if (type == P_MENU)
587                         break;
588         }
589         return menu;
590 }
591 
592 static void get_def_str(struct gstr *r, const struct menu *menu)
593 {
594         str_printf(r, "Defined at %s:%d\n",
595                    menu->filename, menu->lineno);
596 }
597 
598 static void get_dep_str(struct gstr *r, const struct expr *expr,
599                         const char *prefix)
600 {
601         if (!expr_is_yes(expr)) {
602                 str_append(r, prefix);
603                 expr_gstr_print(expr, r);
604                 str_append(r, "\n");
605         }
606 }
607 
608 int __attribute__((weak)) get_jump_key_char(void)
609 {
610         return -1;
611 }
612 
613 static void get_prompt_str(struct gstr *r, struct property *prop,
614                            struct list_head *head)
615 {
616         int i, j;
617         struct menu *submenu[8], *menu, *location = NULL;
618         struct jump_key *jump = NULL;
619 
620         str_printf(r, "  Prompt: %s\n", prop->text);
621 
622         get_dep_str(r, prop->menu->dep, "  Depends on: ");
623         /*
624          * Most prompts in Linux have visibility that exactly matches their
625          * dependencies. For these, we print only the dependencies to improve
626          * readability. However, prompts with inline "if" expressions and
627          * prompts with a parent that has a "visible if" expression have
628          * differing dependencies and visibility. In these rare cases, we
629          * print both.
630          */
631         if (!expr_eq(prop->menu->dep, prop->visible.expr))
632                 get_dep_str(r, prop->visible.expr, "  Visible if: ");
633 
634         menu = prop->menu;
635         for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent) {
636                 submenu[i++] = menu;
637                 if (location == NULL && menu_is_visible(menu))
638                         location = menu;
639         }
640         if (head && location) {
641                 jump = xmalloc(sizeof(struct jump_key));
642                 jump->target = location;
643                 list_add_tail(&jump->entries, head);
644         }
645 
646         str_printf(r, "  Location:\n");
647         for (j = 0; --i >= 0; j++) {
648                 int jk = -1;
649                 int indent = 2 * j + 4;
650 
651                 menu = submenu[i];
652                 if (jump && menu == location) {
653                         jump->offset = strlen(r->s);
654                         jk = get_jump_key_char();
655                 }
656 
657                 if (jk >= 0) {
658                         str_printf(r, "(%c)", jk);
659                         indent -= 3;
660                 }
661 
662                 str_printf(r, "%*c-> %s", indent, ' ', menu_get_prompt(menu));
663                 if (menu->sym) {
664                         str_printf(r, " (%s [=%s])", menu->sym->name ?
665                                 menu->sym->name : "<choice>",
666                                 sym_get_string_value(menu->sym));
667                 }
668                 str_append(r, "\n");
669         }
670 }
671 
672 static void get_symbol_props_str(struct gstr *r, struct symbol *sym,
673                                  enum prop_type tok, const char *prefix)
674 {
675         bool hit = false;
676         struct property *prop;
677 
678         for_all_properties(sym, prop, tok) {
679                 if (!hit) {
680                         str_append(r, prefix);
681                         hit = true;
682                 } else
683                         str_printf(r, " && ");
684                 expr_gstr_print(prop->expr, r);
685         }
686         if (hit)
687                 str_append(r, "\n");
688 }
689 
690 /*
691  * head is optional and may be NULL
692  */
693 static void get_symbol_str(struct gstr *r, struct symbol *sym,
694                     struct list_head *head)
695 {
696         struct property *prop;
697         struct menu *menu;
698 
699         if (sym && sym->name) {
700                 str_printf(r, "Symbol: %s [=%s]\n", sym->name,
701                            sym_get_string_value(sym));
702                 str_printf(r, "Type  : %s\n", sym_type_name(sym->type));
703                 if (sym->type == S_INT || sym->type == S_HEX) {
704                         prop = sym_get_range_prop(sym);
705                         if (prop) {
706                                 str_printf(r, "Range : ");
707                                 expr_gstr_print(prop->expr, r);
708                                 str_append(r, "\n");
709                         }
710                 }
711         }
712 
713         /* Print the definitions with prompts before the ones without */
714         list_for_each_entry(menu, &sym->menus, link) {
715                 if (menu->prompt) {
716                         get_def_str(r, menu);
717                         get_prompt_str(r, menu->prompt, head);
718                 }
719         }
720 
721         list_for_each_entry(menu, &sym->menus, link) {
722                 if (!menu->prompt) {
723                         get_def_str(r, menu);
724                         get_dep_str(r, menu->dep, "  Depends on: ");
725                 }
726         }
727 
728         get_symbol_props_str(r, sym, P_SELECT, "Selects: ");
729         if (sym->rev_dep.expr) {
730                 expr_gstr_print_revdep(sym->rev_dep.expr, r, yes, "Selected by [y]:\n");
731                 expr_gstr_print_revdep(sym->rev_dep.expr, r, mod, "Selected by [m]:\n");
732                 expr_gstr_print_revdep(sym->rev_dep.expr, r, no, "Selected by [n]:\n");
733         }
734 
735         get_symbol_props_str(r, sym, P_IMPLY, "Implies: ");
736         if (sym->implied.expr) {
737                 expr_gstr_print_revdep(sym->implied.expr, r, yes, "Implied by [y]:\n");
738                 expr_gstr_print_revdep(sym->implied.expr, r, mod, "Implied by [m]:\n");
739                 expr_gstr_print_revdep(sym->implied.expr, r, no, "Implied by [n]:\n");
740         }
741 
742         str_append(r, "\n\n");
743 }
744 
745 struct gstr get_relations_str(struct symbol **sym_arr, struct list_head *head)
746 {
747         struct symbol *sym;
748         struct gstr res = str_new();
749         int i;
750 
751         for (i = 0; sym_arr && (sym = sym_arr[i]); i++)
752                 get_symbol_str(&res, sym, head);
753         if (!i)
754                 str_append(&res, "No matches found.\n");
755         return res;
756 }
757 
758 
759 void menu_get_ext_help(struct menu *menu, struct gstr *help)
760 {
761         struct symbol *sym = menu->sym;
762         const char *help_text = nohelp_text;
763 
764         if (menu->help) {
765                 if (sym->name)
766                         str_printf(help, "%s%s:\n\n", CONFIG_, sym->name);
767                 help_text = menu->help;
768         }
769         str_printf(help, "%s\n", help_text);
770         if (sym)
771                 get_symbol_str(help, sym, NULL);
772 }
773 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php