menu.c 22 KB

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