home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / src / linux-headers-2.6.28-15 / scripts / kconfig / menu.c < prev    next >
Encoding:
C/C++ Source or Header  |  2008-12-24  |  11.3 KB  |  454 lines

  1. /*
  2.  * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
  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. struct menu rootmenu;
  13. static struct menu **last_entry_ptr;
  14.  
  15. struct file *file_list;
  16. struct file *current_file;
  17.  
  18. void menu_warn(struct menu *menu, const char *fmt, ...)
  19. {
  20.     va_list ap;
  21.     va_start(ap, fmt);
  22.     fprintf(stderr, "%s:%d:warning: ", menu->file->name, menu->lineno);
  23.     vfprintf(stderr, fmt, ap);
  24.     fprintf(stderr, "\n");
  25.     va_end(ap);
  26. }
  27.  
  28. static void prop_warn(struct property *prop, const char *fmt, ...)
  29. {
  30.     va_list ap;
  31.     va_start(ap, fmt);
  32.     fprintf(stderr, "%s:%d:warning: ", prop->file->name, prop->lineno);
  33.     vfprintf(stderr, fmt, ap);
  34.     fprintf(stderr, "\n");
  35.     va_end(ap);
  36. }
  37.  
  38. void menu_init(void)
  39. {
  40.     current_entry = current_menu = &rootmenu;
  41.     last_entry_ptr = &rootmenu.list;
  42. }
  43.  
  44. void menu_add_entry(struct symbol *sym)
  45. {
  46.     struct menu *menu;
  47.  
  48.     menu = malloc(sizeof(*menu));
  49.     memset(menu, 0, sizeof(*menu));
  50.     menu->sym = sym;
  51.     menu->parent = current_menu;
  52.     menu->file = current_file;
  53.     menu->lineno = zconf_lineno();
  54.  
  55.     *last_entry_ptr = menu;
  56.     last_entry_ptr = &menu->next;
  57.     current_entry = menu;
  58. }
  59.  
  60. void menu_end_entry(void)
  61. {
  62. }
  63.  
  64. struct menu *menu_add_menu(void)
  65. {
  66.     menu_end_entry();
  67.     last_entry_ptr = ¤t_entry->list;
  68.     return current_menu = current_entry;
  69. }
  70.  
  71. void menu_end_menu(void)
  72. {
  73.     last_entry_ptr = ¤t_menu->next;
  74.     current_menu = current_menu->parent;
  75. }
  76.  
  77. struct expr *menu_check_dep(struct expr *e)
  78. {
  79.     if (!e)
  80.         return e;
  81.  
  82.     switch (e->type) {
  83.     case E_NOT:
  84.         e->left.expr = menu_check_dep(e->left.expr);
  85.         break;
  86.     case E_OR:
  87.     case E_AND:
  88.         e->left.expr = menu_check_dep(e->left.expr);
  89.         e->right.expr = menu_check_dep(e->right.expr);
  90.         break;
  91.     case E_SYMBOL:
  92.         /* change 'm' into 'm' && MODULES */
  93.         if (e->left.sym == &symbol_mod)
  94.             return expr_alloc_and(e, expr_alloc_symbol(modules_sym));
  95.         break;
  96.     default:
  97.         break;
  98.     }
  99.     return e;
  100. }
  101.  
  102. void menu_add_dep(struct expr *dep)
  103. {
  104.     current_entry->dep = expr_alloc_and(current_entry->dep, menu_check_dep(dep));
  105. }
  106.  
  107. void menu_set_type(int type)
  108. {
  109.     struct symbol *sym = current_entry->sym;
  110.  
  111.     if (sym->type == type)
  112.         return;
  113.     if (sym->type == S_UNKNOWN) {
  114.         sym->type = type;
  115.         return;
  116.     }
  117.     menu_warn(current_entry, "type of '%s' redefined from '%s' to '%s'",
  118.         sym->name ? sym->name : "<choice>",
  119.         sym_type_name(sym->type), sym_type_name(type));
  120. }
  121.  
  122. struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep)
  123. {
  124.     struct property *prop = prop_alloc(type, current_entry->sym);
  125.  
  126.     prop->menu = current_entry;
  127.     prop->expr = expr;
  128.     prop->visible.expr = menu_check_dep(dep);
  129.  
  130.     if (prompt) {
  131.         if (isspace(*prompt)) {
  132.             prop_warn(prop, "leading whitespace ignored");
  133.             while (isspace(*prompt))
  134.                 prompt++;
  135.         }
  136.         if (current_entry->prompt)
  137.             prop_warn(prop, "prompt redefined");
  138.         current_entry->prompt = prop;
  139.     }
  140.     prop->text = prompt;
  141.  
  142.     return prop;
  143. }
  144.  
  145. struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep)
  146. {
  147.     return menu_add_prop(type, prompt, NULL, dep);
  148. }
  149.  
  150. void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep)
  151. {
  152.     menu_add_prop(type, NULL, expr, dep);
  153. }
  154.  
  155. void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep)
  156. {
  157.     menu_add_prop(type, NULL, expr_alloc_symbol(sym), dep);
  158. }
  159.  
  160. void menu_add_option(int token, char *arg)
  161. {
  162.     struct property *prop;
  163.  
  164.     switch (token) {
  165.     case T_OPT_MODULES:
  166.         prop = prop_alloc(P_DEFAULT, modules_sym);
  167.         prop->expr = expr_alloc_symbol(current_entry->sym);
  168.         break;
  169.     case T_OPT_DEFCONFIG_LIST:
  170.         if (!sym_defconfig_list)
  171.             sym_defconfig_list = current_entry->sym;
  172.         else if (sym_defconfig_list != current_entry->sym)
  173.             zconf_error("trying to redefine defconfig symbol");
  174.         break;
  175.     case T_OPT_ENV:
  176.         prop_add_env(arg);
  177.         break;
  178.     }
  179. }
  180.  
  181. static int menu_range_valid_sym(struct symbol *sym, struct symbol *sym2)
  182. {
  183.     return sym2->type == S_INT || sym2->type == S_HEX ||
  184.            (sym2->type == S_UNKNOWN && sym_string_valid(sym, sym2->name));
  185. }
  186.  
  187. void sym_check_prop(struct symbol *sym)
  188. {
  189.     struct property *prop;
  190.     struct symbol *sym2;
  191.     for (prop = sym->prop; prop; prop = prop->next) {
  192.         switch (prop->type) {
  193.         case P_DEFAULT:
  194.             if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) &&
  195.                 prop->expr->type != E_SYMBOL)
  196.                 prop_warn(prop,
  197.                     "default for config symbol '%'"
  198.                     " must be a single symbol", sym->name);
  199.             break;
  200.         case P_SELECT:
  201.             sym2 = prop_get_symbol(prop);
  202.             if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE)
  203.                 prop_warn(prop,
  204.                     "config symbol '%s' uses select, but is "
  205.                     "not boolean or tristate", sym->name);
  206.             else if (sym2->type != S_UNKNOWN &&
  207.                      sym2->type != S_BOOLEAN &&
  208.                      sym2->type != S_TRISTATE)
  209.                 prop_warn(prop,
  210.                     "'%s' has wrong type. 'select' only "
  211.                     "accept arguments of boolean and "
  212.                     "tristate type", sym2->name);
  213.             break;
  214.         case P_RANGE:
  215.             if (sym->type != S_INT && sym->type != S_HEX)
  216.                 prop_warn(prop, "range is only allowed "
  217.                                 "for int or hex symbols");
  218.             if (!menu_range_valid_sym(sym, prop->expr->left.sym) ||
  219.                 !menu_range_valid_sym(sym, prop->expr->right.sym))
  220.                 prop_warn(prop, "range is invalid");
  221.             break;
  222.         default:
  223.             ;
  224.         }
  225.     }
  226. }
  227.  
  228. void menu_finalize(struct menu *parent)
  229. {
  230.     struct menu *menu, *last_menu;
  231.     struct symbol *sym;
  232.     struct property *prop;
  233.     struct expr *parentdep, *basedep, *dep, *dep2, **ep;
  234.  
  235.     sym = parent->sym;
  236.     if (parent->list) {
  237.         if (sym && sym_is_choice(sym)) {
  238.             if (sym->type == S_UNKNOWN) {
  239.                 /* find the first choice value to find out choice type */
  240.                 current_entry = parent;
  241.                 for (menu = parent->list; menu; menu = menu->next) {
  242.                     if (menu->sym && menu->sym->type != S_UNKNOWN) {
  243.                         menu_set_type(menu->sym->type);
  244.                         break;
  245.                     }
  246.                 }
  247.             }
  248.             /* set the type of the remaining choice values */
  249.             for (menu = parent->list; menu; menu = menu->next) {
  250.                 current_entry = menu;
  251.                 if (menu->sym && menu->sym->type == S_UNKNOWN)
  252.                     menu_set_type(sym->type);
  253.             }
  254.             parentdep = expr_alloc_symbol(sym);
  255.         } else if (parent->prompt)
  256.             parentdep = parent->prompt->visible.expr;
  257.         else
  258.             parentdep = parent->dep;
  259.  
  260.         for (menu = parent->list; menu; menu = menu->next) {
  261.             basedep = expr_transform(menu->dep);
  262.             basedep = expr_alloc_and(expr_copy(parentdep), basedep);
  263.             basedep = expr_eliminate_dups(basedep);
  264.             menu->dep = basedep;
  265.             if (menu->sym)
  266.                 prop = menu->sym->prop;
  267.             else
  268.                 prop = menu->prompt;
  269.             for (; prop; prop = prop->next) {
  270.                 if (prop->menu != menu)
  271.                     continue;
  272.                 dep = expr_transform(prop->visible.expr);
  273.                 dep = expr_alloc_and(expr_copy(basedep), dep);
  274.                 dep = expr_eliminate_dups(dep);
  275.                 if (menu->sym && menu->sym->type != S_TRISTATE)
  276.                     dep = expr_trans_bool(dep);
  277.                 prop->visible.expr = dep;
  278.                 if (prop->type == P_SELECT) {
  279.                     struct symbol *es = prop_get_symbol(prop);
  280.                     es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr,
  281.                             expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep)));
  282.                 }
  283.             }
  284.         }
  285.         for (menu = parent->list; menu; menu = menu->next)
  286.             menu_finalize(menu);
  287.     } else if (sym) {
  288.         basedep = parent->prompt ? parent->prompt->visible.expr : NULL;
  289.         basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no);
  290.         basedep = expr_eliminate_dups(expr_transform(basedep));
  291.         last_menu = NULL;
  292.         for (menu = parent->next; menu; menu = menu->next) {
  293.             dep = menu->prompt ? menu->prompt->visible.expr : menu->dep;
  294.             if (!expr_contains_symbol(dep, sym))
  295.                 break;
  296.             if (expr_depends_symbol(dep, sym))
  297.                 goto next;
  298.             dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no);
  299.             dep = expr_eliminate_dups(expr_transform(dep));
  300.             dep2 = expr_copy(basedep);
  301.             expr_eliminate_eq(&dep, &dep2);
  302.             expr_free(dep);
  303.             if (!expr_is_yes(dep2)) {
  304.                 expr_free(dep2);
  305.                 break;
  306.             }
  307.             expr_free(dep2);
  308.         next:
  309.             menu_finalize(menu);
  310.             menu->parent = parent;
  311.             last_menu = menu;
  312.         }
  313.         if (last_menu) {
  314.             parent->list = parent->next;
  315.             parent->next = last_menu->next;
  316.             last_menu->next = NULL;
  317.         }
  318.     }
  319.     for (menu = parent->list; menu; menu = menu->next) {
  320.         if (sym && sym_is_choice(sym) &&
  321.             menu->sym && !sym_is_choice_value(menu->sym)) {
  322.             current_entry = menu;
  323.             menu->sym->flags |= SYMBOL_CHOICEVAL;
  324.             if (!menu->prompt)
  325.                 menu_warn(menu, "choice value must have a prompt");
  326.             for (prop = menu->sym->prop; prop; prop = prop->next) {
  327.                 if (prop->type == P_DEFAULT)
  328.                     prop_warn(prop, "defaults for choice "
  329.                           "values not supported");
  330.                 if (prop->menu == menu)
  331.                     continue;
  332.                 if (prop->type == P_PROMPT &&
  333.                     prop->menu->parent->sym != sym)
  334.                     prop_warn(prop, "choice value used outside its choice group");
  335.             }
  336.             /* Non-tristate choice values of tristate choices must
  337.              * depend on the choice being set to Y. The choice
  338.              * values' dependencies were propagated to their
  339.              * properties above, so the change here must be re-
  340.              * propagated.
  341.              */
  342.             if (sym->type == S_TRISTATE && menu->sym->type != S_TRISTATE) {
  343.                 basedep = expr_alloc_comp(E_EQUAL, sym, &symbol_yes);
  344.                 menu->dep = expr_alloc_and(basedep, menu->dep);
  345.                 for (prop = menu->sym->prop; prop; prop = prop->next) {
  346.                     if (prop->menu != menu)
  347.                         continue;
  348.                     prop->visible.expr = expr_alloc_and(expr_copy(basedep),
  349.                                         prop->visible.expr);
  350.                 }
  351.             }
  352.             menu_add_symbol(P_CHOICE, sym, NULL);
  353.             prop = sym_get_choice_prop(sym);
  354.             for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr)
  355.                 ;
  356.             *ep = expr_alloc_one(E_LIST, NULL);
  357.             (*ep)->right.sym = menu->sym;
  358.         }
  359.         if (menu->list && (!menu->prompt || !menu->prompt->text)) {
  360.             for (last_menu = menu->list; ; last_menu = last_menu->next) {
  361.                 last_menu->parent = parent;
  362.                 if (!last_menu->next)
  363.                     break;
  364.             }
  365.             last_menu->next = menu->next;
  366.             menu->next = menu->list;
  367.             menu->list = NULL;
  368.         }
  369.     }
  370.  
  371.     if (sym && !(sym->flags & SYMBOL_WARNED)) {
  372.         if (sym->type == S_UNKNOWN)
  373.             menu_warn(parent, "config symbol defined without type");
  374.  
  375.         if (sym_is_choice(sym) && !parent->prompt)
  376.             menu_warn(parent, "choice must have a prompt");
  377.  
  378.         /* Check properties connected to this symbol */
  379.         sym_check_prop(sym);
  380.         sym->flags |= SYMBOL_WARNED;
  381.     }
  382.  
  383.     if (sym && !sym_is_optional(sym) && parent->prompt) {
  384.         sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr,
  385.                 expr_alloc_and(parent->prompt->visible.expr,
  386.                     expr_alloc_symbol(&symbol_mod)));
  387.     }
  388. }
  389.  
  390. bool menu_is_visible(struct menu *menu)
  391. {
  392.     struct menu *child;
  393.     struct symbol *sym;
  394.     tristate visible;
  395.  
  396.     if (!menu->prompt)
  397.         return false;
  398.     sym = menu->sym;
  399.     if (sym) {
  400.         sym_calc_value(sym);
  401.         visible = menu->prompt->visible.tri;
  402.     } else
  403.         visible = menu->prompt->visible.tri = expr_calc_value(menu->prompt->visible.expr);
  404.  
  405.     if (visible != no)
  406.         return true;
  407.     if (!sym || sym_get_tristate_value(menu->sym) == no)
  408.         return false;
  409.  
  410.     for (child = menu->list; child; child = child->next)
  411.         if (menu_is_visible(child))
  412.             return true;
  413.     return false;
  414. }
  415.  
  416. const char *menu_get_prompt(struct menu *menu)
  417. {
  418.     if (menu->prompt)
  419.         return menu->prompt->text;
  420.     else if (menu->sym)
  421.         return menu->sym->name;
  422.     return NULL;
  423. }
  424.  
  425. struct menu *menu_get_root_menu(struct menu *menu)
  426. {
  427.     return &rootmenu;
  428. }
  429.  
  430. struct menu *menu_get_parent_menu(struct menu *menu)
  431. {
  432.     enum prop_type type;
  433.  
  434.     for (; menu != &rootmenu; menu = menu->parent) {
  435.         type = menu->prompt ? menu->prompt->type : 0;
  436.         if (type == P_MENU)
  437.             break;
  438.     }
  439.     return menu;
  440. }
  441.  
  442. bool menu_has_help(struct menu *menu)
  443. {
  444.     return menu->help != NULL;
  445. }
  446.  
  447. const char *menu_get_help(struct menu *menu)
  448. {
  449.     if (menu->help)
  450.         return menu->help;
  451.     else
  452.         return "";
  453. }
  454.