|
|
1.1 ! root 1: /* ! 2: * Copyright (C) 2002 Roman Zippel <[email protected]> ! 3: * Released under the terms of the GNU GPL v2.0. ! 4: */ ! 5: ! 6: #include <stdlib.h> ! 7: #include <string.h> ! 8: ! 9: #define LKC_DIRECT_LINK ! 10: #include "lkc.h" ! 11: ! 12: static const char nohelp_text[] = N_( ! 13: "There is no help available for this option.\n"); ! 14: ! 15: struct menu rootmenu; ! 16: static struct menu **last_entry_ptr; ! 17: ! 18: struct file *file_list; ! 19: struct file *current_file; ! 20: ! 21: void menu_warn(struct menu *menu, const char *fmt, ...) ! 22: { ! 23: va_list ap; ! 24: va_start(ap, fmt); ! 25: fprintf(stderr, "%s:%d:warning: ", menu->file->name, menu->lineno); ! 26: vfprintf(stderr, fmt, ap); ! 27: fprintf(stderr, "\n"); ! 28: va_end(ap); ! 29: } ! 30: ! 31: static void prop_warn(struct property *prop, const char *fmt, ...) ! 32: { ! 33: va_list ap; ! 34: va_start(ap, fmt); ! 35: fprintf(stderr, "%s:%d:warning: ", prop->file->name, prop->lineno); ! 36: vfprintf(stderr, fmt, ap); ! 37: fprintf(stderr, "\n"); ! 38: va_end(ap); ! 39: } ! 40: ! 41: void _menu_init(void) ! 42: { ! 43: current_entry = current_menu = &rootmenu; ! 44: last_entry_ptr = &rootmenu.list; ! 45: } ! 46: ! 47: void menu_add_entry(struct symbol *sym) ! 48: { ! 49: struct menu *menu; ! 50: ! 51: menu = malloc(sizeof(*menu)); ! 52: memset(menu, 0, sizeof(*menu)); ! 53: menu->sym = sym; ! 54: menu->parent = current_menu; ! 55: menu->file = current_file; ! 56: menu->lineno = zconf_lineno(); ! 57: ! 58: *last_entry_ptr = menu; ! 59: last_entry_ptr = &menu->next; ! 60: current_entry = menu; ! 61: if (sym) ! 62: menu_add_symbol(P_SYMBOL, sym, NULL); ! 63: } ! 64: ! 65: void menu_end_entry(void) ! 66: { ! 67: } ! 68: ! 69: struct menu *menu_add_menu(void) ! 70: { ! 71: menu_end_entry(); ! 72: last_entry_ptr = ¤t_entry->list; ! 73: return current_menu = current_entry; ! 74: } ! 75: ! 76: void menu_end_menu(void) ! 77: { ! 78: last_entry_ptr = ¤t_menu->next; ! 79: current_menu = current_menu->parent; ! 80: } ! 81: ! 82: static struct expr *menu_check_dep(struct expr *e) ! 83: { ! 84: if (!e) ! 85: return e; ! 86: ! 87: switch (e->type) { ! 88: case E_NOT: ! 89: e->left.expr = menu_check_dep(e->left.expr); ! 90: break; ! 91: case E_OR: ! 92: case E_AND: ! 93: e->left.expr = menu_check_dep(e->left.expr); ! 94: e->right.expr = menu_check_dep(e->right.expr); ! 95: break; ! 96: case E_SYMBOL: ! 97: /* change 'm' into 'm' && MODULES */ ! 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: ! 107: void menu_add_dep(struct expr *dep) ! 108: { ! 109: current_entry->dep = expr_alloc_and(current_entry->dep, menu_check_dep(dep)); ! 110: } ! 111: ! 112: void 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, "type of '%s' redefined from '%s' to '%s'", ! 123: sym->name ? sym->name : "<choice>", ! 124: sym_type_name(sym->type), sym_type_name(type)); ! 125: } ! 126: ! 127: struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep) ! 128: { ! 129: struct property *prop = prop_alloc(type, current_entry->sym); ! 130: ! 131: prop->menu = current_entry; ! 132: prop->expr = expr; ! 133: prop->visible.expr = menu_check_dep(dep); ! 134: ! 135: if (prompt) { ! 136: if (isspace(*prompt)) { ! 137: prop_warn(prop, "leading whitespace ignored"); ! 138: while (isspace(*prompt)) ! 139: prompt++; ! 140: } ! 141: if (current_entry->prompt && current_entry != &rootmenu) ! 142: prop_warn(prop, "prompt redefined"); ! 143: ! 144: /* Apply all upper menus' visibilities to actual prompts. */ ! 145: if(type == P_PROMPT) { ! 146: struct menu *menu = current_entry; ! 147: ! 148: while ((menu = menu->parent) != NULL) { ! 149: if (!menu->visibility) ! 150: continue; ! 151: prop->visible.expr ! 152: = expr_alloc_and(prop->visible.expr, ! 153: menu->visibility); ! 154: } ! 155: } ! 156: ! 157: current_entry->prompt = prop; ! 158: } ! 159: prop->text = prompt; ! 160: ! 161: return prop; ! 162: } ! 163: ! 164: struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep) ! 165: { ! 166: return menu_add_prop(type, prompt, NULL, dep); ! 167: } ! 168: ! 169: void menu_add_visibility(struct expr *expr) ! 170: { ! 171: current_entry->visibility = expr_alloc_and(current_entry->visibility, ! 172: expr); ! 173: } ! 174: ! 175: void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep) ! 176: { ! 177: menu_add_prop(type, NULL, expr, dep); ! 178: } ! 179: ! 180: void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep) ! 181: { ! 182: menu_add_prop(type, NULL, expr_alloc_symbol(sym), dep); ! 183: } ! 184: ! 185: void menu_add_option(int token, char *arg) ! 186: { ! 187: struct property *prop; ! 188: ! 189: switch (token) { ! 190: case T_OPT_MODULES: ! 191: prop = prop_alloc(P_DEFAULT, modules_sym); ! 192: prop->expr = expr_alloc_symbol(current_entry->sym); ! 193: break; ! 194: case T_OPT_DEFCONFIG_LIST: ! 195: if (!sym_defconfig_list) ! 196: sym_defconfig_list = current_entry->sym; ! 197: else if (sym_defconfig_list != current_entry->sym) ! 198: zconf_error("trying to redefine defconfig symbol"); ! 199: break; ! 200: case T_OPT_ENV: ! 201: prop_add_env(arg); ! 202: break; ! 203: } ! 204: } ! 205: ! 206: static int menu_validate_number(struct symbol *sym, struct symbol *sym2) ! 207: { ! 208: return sym2->type == S_INT || sym2->type == S_HEX || ! 209: (sym2->type == S_UNKNOWN && sym_string_valid(sym, sym2->name)); ! 210: } ! 211: ! 212: static void sym_check_prop(struct symbol *sym) ! 213: { ! 214: struct property *prop; ! 215: struct symbol *sym2; ! 216: for (prop = sym->prop; prop; prop = prop->next) { ! 217: switch (prop->type) { ! 218: case P_DEFAULT: ! 219: if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) && ! 220: prop->expr->type != E_SYMBOL) ! 221: prop_warn(prop, ! 222: "default for config symbol '%s'" ! 223: " must be a single symbol", sym->name); ! 224: if (prop->expr->type != E_SYMBOL) ! 225: break; ! 226: sym2 = prop_get_symbol(prop); ! 227: if (sym->type == S_HEX || sym->type == S_INT) { ! 228: if (!menu_validate_number(sym, sym2)) ! 229: prop_warn(prop, ! 230: "'%s': number is invalid", ! 231: sym->name); ! 232: } ! 233: break; ! 234: case P_SELECT: ! 235: sym2 = prop_get_symbol(prop); ! 236: if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE) ! 237: prop_warn(prop, ! 238: "config symbol '%s' uses select, but is " ! 239: "not boolean or tristate", sym->name); ! 240: else if (sym2->type != S_UNKNOWN && ! 241: sym2->type != S_BOOLEAN && ! 242: sym2->type != S_TRISTATE) ! 243: prop_warn(prop, ! 244: "'%s' has wrong type. 'select' only " ! 245: "accept arguments of boolean and " ! 246: "tristate type", sym2->name); ! 247: break; ! 248: case P_RANGE: ! 249: if (sym->type != S_INT && sym->type != S_HEX) ! 250: prop_warn(prop, "range is only allowed " ! 251: "for int or hex symbols"); ! 252: if (!menu_validate_number(sym, prop->expr->left.sym) || ! 253: !menu_validate_number(sym, prop->expr->right.sym)) ! 254: prop_warn(prop, "range is invalid"); ! 255: break; ! 256: default: ! 257: ; ! 258: } ! 259: } ! 260: } ! 261: ! 262: void menu_finalize(struct menu *parent) ! 263: { ! 264: struct menu *menu, *last_menu; ! 265: struct symbol *sym; ! 266: struct property *prop; ! 267: struct expr *parentdep, *basedep, *dep, *dep2, **ep; ! 268: ! 269: sym = parent->sym; ! 270: if (parent->list) { ! 271: if (sym && sym_is_choice(sym)) { ! 272: if (sym->type == S_UNKNOWN) { ! 273: /* find the first choice value to find out choice type */ ! 274: current_entry = parent; ! 275: for (menu = parent->list; menu; menu = menu->next) { ! 276: if (menu->sym && menu->sym->type != S_UNKNOWN) { ! 277: menu_set_type(menu->sym->type); ! 278: break; ! 279: } ! 280: } ! 281: } ! 282: /* set the type of the remaining choice values */ ! 283: for (menu = parent->list; menu; menu = menu->next) { ! 284: current_entry = menu; ! 285: if (menu->sym && menu->sym->type == S_UNKNOWN) ! 286: menu_set_type(sym->type); ! 287: } ! 288: parentdep = expr_alloc_symbol(sym); ! 289: } else if (parent->prompt) ! 290: parentdep = parent->prompt->visible.expr; ! 291: else ! 292: parentdep = parent->dep; ! 293: ! 294: for (menu = parent->list; menu; menu = menu->next) { ! 295: basedep = expr_transform(menu->dep); ! 296: basedep = expr_alloc_and(expr_copy(parentdep), basedep); ! 297: basedep = expr_eliminate_dups(basedep); ! 298: menu->dep = basedep; ! 299: if (menu->sym) ! 300: prop = menu->sym->prop; ! 301: else ! 302: prop = menu->prompt; ! 303: for (; prop; prop = prop->next) { ! 304: if (prop->menu != menu) ! 305: continue; ! 306: dep = expr_transform(prop->visible.expr); ! 307: dep = expr_alloc_and(expr_copy(basedep), dep); ! 308: dep = expr_eliminate_dups(dep); ! 309: if (menu->sym && menu->sym->type != S_TRISTATE) ! 310: dep = expr_trans_bool(dep); ! 311: prop->visible.expr = dep; ! 312: if (prop->type == P_SELECT) { ! 313: struct symbol *es = prop_get_symbol(prop); ! 314: es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr, ! 315: expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep))); ! 316: } ! 317: } ! 318: } ! 319: for (menu = parent->list; menu; menu = menu->next) ! 320: menu_finalize(menu); ! 321: } else if (sym) { ! 322: basedep = parent->prompt ? parent->prompt->visible.expr : NULL; ! 323: basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no); ! 324: basedep = expr_eliminate_dups(expr_transform(basedep)); ! 325: last_menu = NULL; ! 326: for (menu = parent->next; menu; menu = menu->next) { ! 327: dep = menu->prompt ? menu->prompt->visible.expr : menu->dep; ! 328: if (!expr_contains_symbol(dep, sym)) ! 329: break; ! 330: if (expr_depends_symbol(dep, sym)) ! 331: goto next; ! 332: dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no); ! 333: dep = expr_eliminate_dups(expr_transform(dep)); ! 334: dep2 = expr_copy(basedep); ! 335: expr_eliminate_eq(&dep, &dep2); ! 336: expr_free(dep); ! 337: if (!expr_is_yes(dep2)) { ! 338: expr_free(dep2); ! 339: break; ! 340: } ! 341: expr_free(dep2); ! 342: next: ! 343: menu_finalize(menu); ! 344: menu->parent = parent; ! 345: last_menu = menu; ! 346: } ! 347: if (last_menu) { ! 348: parent->list = parent->next; ! 349: parent->next = last_menu->next; ! 350: last_menu->next = NULL; ! 351: } ! 352: ! 353: sym->dir_dep.expr = parent->dep; ! 354: } ! 355: for (menu = parent->list; menu; menu = menu->next) { ! 356: if (sym && sym_is_choice(sym) && ! 357: menu->sym && !sym_is_choice_value(menu->sym)) { ! 358: current_entry = menu; ! 359: menu->sym->flags |= SYMBOL_CHOICEVAL; ! 360: if (!menu->prompt) ! 361: menu_warn(menu, "choice value must have a prompt"); ! 362: for (prop = menu->sym->prop; prop; prop = prop->next) { ! 363: if (prop->type == P_DEFAULT) ! 364: prop_warn(prop, "defaults for choice " ! 365: "values not supported"); ! 366: if (prop->menu == menu) ! 367: continue; ! 368: if (prop->type == P_PROMPT && ! 369: prop->menu->parent->sym != sym) ! 370: prop_warn(prop, "choice value used outside its choice group"); ! 371: } ! 372: /* Non-tristate choice values of tristate choices must ! 373: * depend on the choice being set to Y. The choice ! 374: * values' dependencies were propagated to their ! 375: * properties above, so the change here must be re- ! 376: * propagated. ! 377: */ ! 378: if (sym->type == S_TRISTATE && menu->sym->type != S_TRISTATE) { ! 379: basedep = expr_alloc_comp(E_EQUAL, sym, &symbol_yes); ! 380: menu->dep = expr_alloc_and(basedep, menu->dep); ! 381: for (prop = menu->sym->prop; prop; prop = prop->next) { ! 382: if (prop->menu != menu) ! 383: continue; ! 384: prop->visible.expr = expr_alloc_and(expr_copy(basedep), ! 385: prop->visible.expr); ! 386: } ! 387: } ! 388: menu_add_symbol(P_CHOICE, sym, NULL); ! 389: prop = sym_get_choice_prop(sym); ! 390: for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr) ! 391: ; ! 392: *ep = expr_alloc_one(E_LIST, NULL); ! 393: (*ep)->right.sym = menu->sym; ! 394: } ! 395: if (menu->list && (!menu->prompt || !menu->prompt->text)) { ! 396: for (last_menu = menu->list; ; last_menu = last_menu->next) { ! 397: last_menu->parent = parent; ! 398: if (!last_menu->next) ! 399: break; ! 400: } ! 401: last_menu->next = menu->next; ! 402: menu->next = menu->list; ! 403: menu->list = NULL; ! 404: } ! 405: } ! 406: ! 407: if (sym && !(sym->flags & SYMBOL_WARNED)) { ! 408: if (sym->type == S_UNKNOWN) ! 409: menu_warn(parent, "config symbol defined without type"); ! 410: ! 411: if (sym_is_choice(sym) && !parent->prompt) ! 412: menu_warn(parent, "choice must have a prompt"); ! 413: ! 414: /* Check properties connected to this symbol */ ! 415: sym_check_prop(sym); ! 416: sym->flags |= SYMBOL_WARNED; ! 417: } ! 418: ! 419: if (sym && !sym_is_optional(sym) && parent->prompt) { ! 420: sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr, ! 421: expr_alloc_and(parent->prompt->visible.expr, ! 422: expr_alloc_symbol(&symbol_mod))); ! 423: } ! 424: } ! 425: ! 426: bool menu_has_prompt(struct menu *menu) ! 427: { ! 428: if (!menu->prompt) ! 429: return false; ! 430: return true; ! 431: } ! 432: ! 433: bool menu_is_visible(struct menu *menu) ! 434: { ! 435: struct menu *child; ! 436: struct symbol *sym; ! 437: tristate visible; ! 438: ! 439: if (!menu->prompt) ! 440: return false; ! 441: ! 442: if (menu->visibility) { ! 443: if (expr_calc_value(menu->visibility) == no) ! 444: return no; ! 445: } ! 446: ! 447: sym = menu->sym; ! 448: if (sym) { ! 449: sym_calc_value(sym); ! 450: visible = menu->prompt->visible.tri; ! 451: } else ! 452: visible = menu->prompt->visible.tri = expr_calc_value(menu->prompt->visible.expr); ! 453: ! 454: if (visible != no) ! 455: return true; ! 456: ! 457: if (!sym || sym_get_tristate_value(menu->sym) == no) ! 458: return false; ! 459: ! 460: for (child = menu->list; child; child = child->next) { ! 461: if (menu_is_visible(child)) { ! 462: if (sym) ! 463: sym->flags |= SYMBOL_DEF_USER; ! 464: return true; ! 465: } ! 466: } ! 467: ! 468: return false; ! 469: } ! 470: ! 471: const char *menu_get_prompt(struct menu *menu) ! 472: { ! 473: if (menu->prompt) ! 474: return menu->prompt->text; ! 475: else if (menu->sym) ! 476: return menu->sym->name; ! 477: return NULL; ! 478: } ! 479: ! 480: struct menu *menu_get_root_menu(struct menu *menu) ! 481: { ! 482: return &rootmenu; ! 483: } ! 484: ! 485: struct menu *menu_get_parent_menu(struct menu *menu) ! 486: { ! 487: enum prop_type type; ! 488: ! 489: for (; menu != &rootmenu; menu = menu->parent) { ! 490: type = menu->prompt ? menu->prompt->type : 0; ! 491: if (type == P_MENU) ! 492: break; ! 493: } ! 494: return menu; ! 495: } ! 496: ! 497: bool menu_has_help(struct menu *menu) ! 498: { ! 499: return menu->help != NULL; ! 500: } ! 501: ! 502: const char *menu_get_help(struct menu *menu) ! 503: { ! 504: if (menu->help) ! 505: return menu->help; ! 506: else ! 507: return ""; ! 508: } ! 509: ! 510: static void get_prompt_str(struct gstr *r, struct property *prop) ! 511: { ! 512: int i, j; ! 513: struct menu *submenu[8], *menu; ! 514: ! 515: str_printf(r, _("Prompt: %s\n"), _(prop->text)); ! 516: str_printf(r, _(" Defined at %s:%d\n"), prop->menu->file->name, ! 517: prop->menu->lineno); ! 518: if (!expr_is_yes(prop->visible.expr)) { ! 519: str_append(r, _(" Depends on: ")); ! 520: expr_gstr_print(prop->visible.expr, r); ! 521: str_append(r, "\n"); ! 522: } ! 523: menu = prop->menu->parent; ! 524: for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent) ! 525: submenu[i++] = menu; ! 526: if (i > 0) { ! 527: str_printf(r, _(" Location:\n")); ! 528: for (j = 4; --i >= 0; j += 2) { ! 529: menu = submenu[i]; ! 530: str_printf(r, "%*c-> %s", j, ' ', _(menu_get_prompt(menu))); ! 531: if (menu->sym) { ! 532: str_printf(r, " (%s [=%s])", menu->sym->name ? ! 533: menu->sym->name : _("<choice>"), ! 534: sym_get_string_value(menu->sym)); ! 535: } ! 536: str_append(r, "\n"); ! 537: } ! 538: } ! 539: } ! 540: ! 541: void get_symbol_str(struct gstr *r, struct symbol *sym) ! 542: { ! 543: bool hit; ! 544: struct property *prop; ! 545: ! 546: if (sym && sym->name) { ! 547: str_printf(r, "Symbol: %s [=%s]\n", sym->name, ! 548: sym_get_string_value(sym)); ! 549: str_printf(r, "Type : %s\n", sym_type_name(sym->type)); ! 550: if (sym->type == S_INT || sym->type == S_HEX) { ! 551: prop = sym_get_range_prop(sym); ! 552: if (prop) { ! 553: str_printf(r, "Range : "); ! 554: expr_gstr_print(prop->expr, r); ! 555: str_append(r, "\n"); ! 556: } ! 557: } ! 558: } ! 559: for_all_prompts(sym, prop) ! 560: get_prompt_str(r, prop); ! 561: hit = false; ! 562: for_all_properties(sym, prop, P_SELECT) { ! 563: if (!hit) { ! 564: str_append(r, " Selects: "); ! 565: hit = true; ! 566: } else ! 567: str_printf(r, " && "); ! 568: expr_gstr_print(prop->expr, r); ! 569: } ! 570: if (hit) ! 571: str_append(r, "\n"); ! 572: if (sym->rev_dep.expr) { ! 573: str_append(r, _(" Selected by: ")); ! 574: expr_gstr_print(sym->rev_dep.expr, r); ! 575: str_append(r, "\n"); ! 576: } ! 577: str_append(r, "\n\n"); ! 578: } ! 579: ! 580: struct gstr get_relations_str(struct symbol **sym_arr) ! 581: { ! 582: struct symbol *sym; ! 583: struct gstr res = str_new(); ! 584: int i; ! 585: ! 586: for (i = 0; sym_arr && (sym = sym_arr[i]); i++) ! 587: get_symbol_str(&res, sym); ! 588: if (!i) ! 589: str_append(&res, _("No matches found.\n")); ! 590: return res; ! 591: } ! 592: ! 593: ! 594: void menu_get_ext_help(struct menu *menu, struct gstr *help) ! 595: { ! 596: struct symbol *sym = menu->sym; ! 597: ! 598: if (menu_has_help(menu)) { ! 599: if (sym->name) { ! 600: str_printf(help, "%s%s:\n\n", CONFIG_, sym->name); ! 601: str_append(help, _(menu_get_help(menu))); ! 602: str_append(help, "\n"); ! 603: } ! 604: } else { ! 605: str_append(help, nohelp_text); ! 606: } ! 607: if (sym) ! 608: get_symbol_str(help, sym); ! 609: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.