Example #1
0
static struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep)
{
	struct property *prop = prop_alloc(type, current_entry->sym);

	prop->menu = current_entry;
	prop->expr = expr;
	prop->visible.expr = menu_check_dep(dep);

	if (prompt) {
		/* For crostool-NG, a leading pipe followed with spaces
		 * means that pipe shall be removed, and the spaces should
		 * not be trimmed.
		 */
		if (*prompt == '|')
			prompt++;
		else if (isspace(*prompt)) {
			prop_warn(prop, "leading whitespace ignored");
			while (isspace(*prompt))
				prompt++;
		}
		if (current_entry->prompt && current_entry != &rootmenu)
			prop_warn(prop, "prompt redefined");

		/* Apply all upper menus' visibilities to actual prompts. */
		if(type == P_PROMPT) {
			struct menu *menu = current_entry;

			while ((menu = menu->parent) != NULL) {
				struct expr *dup_expr;

				if (!menu->visibility)
					continue;
				/*
				 * Do not add a reference to the
				 * menu's visibility expression but
				 * use a copy of it.  Otherwise the
				 * expression reduction functions
				 * will modify expressions that have
				 * multiple references which can
				 * cause unwanted side effects.
				 */
				dup_expr = expr_copy(menu->visibility);

				prop->visible.expr
					= expr_alloc_and(prop->visible.expr,
							 dup_expr);
			}
		}

		current_entry->prompt = prop;
	}
	prop->text = prompt;

	return prop;
}
Example #2
0
struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep)
{
	struct property *prop = prop_alloc(type, current_entry->sym);

	prop->menu = current_entry;
	prop->expr = expr;
	prop->visible.expr = menu_check_dep(dep);

	if (prompt) {
		/* For crostool-NG, a leading pipe followed with spaces
		 * means that pipe shall be removed, and the spaces should
		 * not be trimmed.
		 */
		if (*prompt == '|')
			prompt++;
		else if (isspace(*prompt)) {
			prop_warn(prop, "leading whitespace ignored");
			while (isspace(*prompt))
				prompt++;
		}
		if (current_entry->prompt && current_entry != &rootmenu)
			prop_warn(prop, "prompt redefined");

		/* Apply all upper menus' visibilities to actual prompts. */
		if(type == P_PROMPT) {
			struct menu *menu = current_entry;

			while ((menu = menu->parent) != NULL) {
				if (!menu->visibility)
					continue;
				prop->visible.expr
					= expr_alloc_and(prop->visible.expr,
							 menu->visibility);
			}
		}

		current_entry->prompt = prop;
	}
	prop->text = prompt;

	return prop;
}
Example #3
0
File: menu.c Project: 274914765/C
void sym_check_prop(struct symbol *sym)
{
    struct property *prop;
    struct symbol *sym2;
    for (prop = sym->prop; prop; prop = prop->next) {
        switch (prop->type) {
        case P_DEFAULT:
            if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) &&
                prop->expr->type != E_SYMBOL)
                prop_warn(prop,
                    "default for config symbol '%'"
                    " must be a single symbol", sym->name);
            break;
        case P_SELECT:
            sym2 = prop_get_symbol(prop);
            if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE)
                prop_warn(prop,
                    "config symbol '%s' uses select, but is "
                    "not boolean or tristate", sym->name);
            else if (sym2->type != S_UNKNOWN &&
                     sym2->type != S_BOOLEAN &&
                     sym2->type != S_TRISTATE)
                prop_warn(prop,
                    "'%s' has wrong type. 'select' only "
                    "accept arguments of boolean and "
                    "tristate type", sym2->name);
            break;
        case P_RANGE:
            if (sym->type != S_INT && sym->type != S_HEX)
                prop_warn(prop, "range is only allowed "
                                "for int or hex symbols");
            if (!menu_range_valid_sym(sym, prop->expr->left.sym) ||
                !menu_range_valid_sym(sym, prop->expr->right.sym))
                prop_warn(prop, "range is invalid");
            break;
        default:
            ;
        }
    }
}
Example #4
0
File: menu.c Project: 274914765/C
struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep)
{
    struct property *prop = prop_alloc(type, current_entry->sym);

    prop->menu = current_entry;
    prop->expr = expr;
    prop->visible.expr = menu_check_dep(dep);

    if (prompt) {
        if (isspace(*prompt)) {
            prop_warn(prop, "leading whitespace ignored");
            while (isspace(*prompt))
                prompt++;
        }
        if (current_entry->prompt)
            prop_warn(prop, "prompt redefined");
        current_entry->prompt = prop;
    }
    prop->text = prompt;

    return prop;
}
Example #5
0
struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep)
{
    struct property *prop = prop_alloc(type, current_entry->sym);

    prop->menu = current_entry;
    prop->expr = expr;
    prop->visible.expr = menu_check_dep(dep);

    if (prompt) {
        if (isspace(*prompt)) {
            prop_warn(prop, "leading whitespace ignored");
            while (isspace(*prompt))
                prompt++;
        }
        if (current_entry->prompt && current_entry != &rootmenu)
            prop_warn(prop, "prompt redefined");

        /* Apply all upper menus' visibilities to actual prompts. */
        if(type == P_PROMPT) {
            struct menu *menu = current_entry;

            while ((menu = menu->parent) != NULL) {
                if (!menu->visibility)
                    continue;
                prop->visible.expr
                    = expr_alloc_and(prop->visible.expr,
                                     menu->visibility);
            }
        }

        current_entry->prompt = prop;
    }
    prop->text = prompt;

    return prop;
}
Example #6
0
void menu_finalize(struct menu *parent)
{
	struct menu *menu, *last_menu;
	struct symbol *sym;
	struct property *prop;
	struct expr *parentdep, *basedep, *dep, *dep2, **ep;

	sym = parent->sym;
	if (parent->list) {
		if (sym && sym_is_choice(sym)) {
			if (sym->type == S_UNKNOWN) {
				/* find the first choice value to find out choice type */
				current_entry = parent;
				for (menu = parent->list; menu; menu = menu->next) {
					if (menu->sym && menu->sym->type != S_UNKNOWN) {
						menu_set_type(menu->sym->type);
						break;
					}
				}
			}
			if (parent->prompt &&
			    !expr_is_yes(parent->prompt->visible.expr)) {
				parent->visibility = expr_alloc_and (parent->visibility,
								     parent->prompt->visible.expr);
			}
			/* set the type of the remaining choice values */
			for (menu = parent->list; menu; menu = menu->next) {
				current_entry = menu;
				if (menu->sym && menu->sym->type == S_UNKNOWN)
					menu_set_type(sym->type);
			}
			parentdep = expr_alloc_symbol(sym);
		} else if (parent->prompt)
			parentdep = parent->prompt->visible.expr;
		else
			parentdep = parent->dep;

		for (menu = parent->list; menu; menu = menu->next) {
			basedep = expr_transform(menu->dep);
			basedep = expr_alloc_and(expr_copy(parentdep), basedep);
			basedep = expr_eliminate_dups(basedep);
			menu->dep = basedep;
			if (menu->sym)
				prop = menu->sym->prop;
			else
				prop = menu->prompt;
			for (; prop; prop = prop->next) {
				if (prop->menu != menu)
					continue;
				dep = expr_transform(prop->visible.expr);
				dep = expr_alloc_and(expr_copy(basedep), dep);
				dep = expr_eliminate_dups(dep);
				if (menu->sym && menu->sym->type != S_TRISTATE)
					dep = expr_trans_bool(dep);
				prop->visible.expr = dep;
				if (prop->type == P_SELECT) {
					struct symbol *es = prop_get_symbol(prop);
					es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr,
							expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep)));
				}
			}
		}
		for (menu = parent->list; menu; menu = menu->next)
			menu_finalize(menu);
	} else if (sym) {
		basedep = parent->prompt ? parent->prompt->visible.expr : NULL;
		basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no);
		basedep = expr_eliminate_dups(expr_transform(basedep));
		last_menu = NULL;
		for (menu = parent->next; menu; menu = menu->next) {
			dep = menu->prompt ? menu->prompt->visible.expr : menu->dep;
			if (!expr_contains_symbol(dep, sym))
				break;
			if (expr_depends_symbol(dep, sym))
				goto next;
			dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no);
			dep = expr_eliminate_dups(expr_transform(dep));
			dep2 = expr_copy(basedep);
			expr_eliminate_eq(&dep, &dep2);
			expr_free(dep);
			if (!expr_is_yes(dep2)) {
				expr_free(dep2);
				break;
			}
			expr_free(dep2);
		next:
			menu_finalize(menu);
			menu->parent = parent;
			last_menu = menu;
		}
		if (last_menu) {
			parent->list = parent->next;
			parent->next = last_menu->next;
			last_menu->next = NULL;
		}

		sym->dir_dep.expr = expr_alloc_or(sym->dir_dep.expr, parent->dep);
	}
	for (menu = parent->list; menu; menu = menu->next) {
		if (sym && sym_is_choice(sym) &&
		    menu->sym && !sym_is_choice_value(menu->sym)) {
			current_entry = menu;
			menu->sym->flags |= SYMBOL_CHOICEVAL;
			if (!menu->prompt)
				menu_warn(menu, "choice value must have a prompt");
			for (prop = menu->sym->prop; prop; prop = prop->next) {
				if (prop->type == P_DEFAULT)
					prop_warn(prop, "defaults for choice "
						  "values not supported");
				if (prop->menu == menu)
					continue;
				if (prop->type == P_PROMPT &&
				    prop->menu->parent->sym != sym)
					prop_warn(prop, "choice value used outside its choice group");
			}
			/* Non-tristate choice values of tristate choices must
			 * depend on the choice being set to Y. The choice
			 * values' dependencies were propagated to their
			 * properties above, so the change here must be re-
			 * propagated.
			 */
			if (sym->type == S_TRISTATE && menu->sym->type != S_TRISTATE) {
				basedep = expr_alloc_comp(E_EQUAL, sym, &symbol_yes);
				menu->dep = expr_alloc_and(basedep, menu->dep);
				for (prop = menu->sym->prop; prop; prop = prop->next) {
					if (prop->menu != menu)
						continue;
					prop->visible.expr = expr_alloc_and(expr_copy(basedep),
									    prop->visible.expr);
				}
			}
			menu_add_symbol(P_CHOICE, sym, NULL);
			prop = sym_get_choice_prop(sym);
			for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr)
				;
			*ep = expr_alloc_one(E_LIST, NULL);
			(*ep)->right.sym = menu->sym;
		}
		if (menu->list && (!menu->prompt || !menu->prompt->text)) {
			for (last_menu = menu->list; ; last_menu = last_menu->next) {
				last_menu->parent = parent;
				if (!last_menu->next)
					break;
			}
			last_menu->next = menu->next;
			menu->next = menu->list;
			menu->list = NULL;
		}
	}

	if (sym && !(sym->flags & SYMBOL_WARNED)) {
		if (sym->type == S_UNKNOWN)
			menu_warn(parent, "config symbol defined without type");

		if (sym_is_choice(sym) && !parent->prompt)
			menu_warn(parent, "choice must have a prompt");

		/* Check properties connected to this symbol */
		sym_check_prop(sym);
		sym->flags |= SYMBOL_WARNED;
	}

	if (sym && !sym_is_optional(sym) && parent->prompt) {
		sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr,
				expr_alloc_and(parent->prompt->visible.expr,
					expr_alloc_symbol(&symbol_mod)));
	}
}
Example #7
0
void menu_finalize(struct menu *parent)
{
    struct menu *menu, *last_menu;
    struct symbol *sym;
    struct property *prop;
    struct expr *parentdep, *basedep, *dep, *dep2, **ep;

    sym = parent->sym;
    if (parent->list) {
        if (sym && sym_is_choice(sym)) {
            /* find the first choice value and find out choice type */
            for (menu = parent->list; menu; menu = menu->next) {
                if (menu->sym) {
                    current_entry = parent;
                    menu_set_type(menu->sym->type);
                    current_entry = menu;
                    menu_set_type(sym->type);
                    break;
                }
            }
            parentdep = expr_alloc_symbol(sym);
        } else if (parent->prompt) {
            parentdep = parent->prompt->visible.expr;
        } else {
            parentdep = parent->dep;
        }

        for (menu = parent->list; menu; menu = menu->next) {
            basedep = expr_transform(menu->dep);
            basedep = expr_alloc_and(expr_copy(parentdep), basedep);
            basedep = expr_eliminate_dups(basedep);
            menu->dep = basedep;
            if (menu->sym) {
                prop = menu->sym->prop;
            } else {
                prop = menu->prompt;
            }
            for (; prop; prop = prop->next) {
                if (prop->menu != menu) {
                    continue;
                }
                dep = expr_transform(prop->visible.expr);
                dep = expr_alloc_and(expr_copy(basedep), dep);
                dep = expr_eliminate_dups(dep);
                if (menu->sym && menu->sym->type != S_TRISTATE) {
                    dep = expr_trans_bool(dep);
                }
                prop->visible.expr = dep;
                if (prop->type == P_SELECT) {
                    struct symbol *es = prop_get_symbol(prop);
                    es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr,
                                                     expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep)));
                }
            }
        }
        for (menu = parent->list; menu; menu = menu->next) {
            menu_finalize(menu);
        }
    } else if (sym) {
        basedep = parent->prompt ? parent->prompt->visible.expr : NULL;
        basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no);
        basedep = expr_eliminate_dups(expr_transform(basedep));
        last_menu = NULL;
        for (menu = parent->next; menu; menu = menu->next) {
            dep = menu->prompt ? menu->prompt->visible.expr : menu->dep;
            if (!expr_contains_symbol(dep, sym)) {
                break;
            }
            if (expr_depends_symbol(dep, sym)) {
                goto next;
            }
            dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no);
            dep = expr_eliminate_dups(expr_transform(dep));
            dep2 = expr_copy(basedep);
            expr_eliminate_eq(&dep, &dep2);
            expr_free(dep);
            if (!expr_is_yes(dep2)) {
                expr_free(dep2);
                break;
            }
            expr_free(dep2);
next:
            menu_finalize(menu);
            menu->parent = parent;
            last_menu = menu;
        }
        if (last_menu) {
            parent->list = parent->next;
            parent->next = last_menu->next;
            last_menu->next = NULL;
        }
    }
    for (menu = parent->list; menu; menu = menu->next) {
        if (sym && sym_is_choice(sym) && menu->sym) {
            menu->sym->flags |= SYMBOL_CHOICEVAL;
            if (!menu->prompt) {
                menu_warn(menu, "choice value must have a prompt");
            }
            for (prop = menu->sym->prop; prop; prop = prop->next) {
                if (prop->type == P_PROMPT && prop->menu != menu) {
                    prop_warn(prop, "choice values "
                              "currently only support a "
                              "single prompt");
                }
                if (prop->type == P_DEFAULT)
                    prop_warn(prop, "defaults for choice "
                              "values not supported");
            }
            current_entry = menu;
            menu_set_type(sym->type);
            menu_add_symbol(P_CHOICE, sym, NULL);
            prop = sym_get_choice_prop(sym);
            for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr)
                ;
            *ep = expr_alloc_one(E_CHOICE, NULL);
            (*ep)->right.sym = menu->sym;
        }
        if (menu->list && (!menu->prompt || !menu->prompt->text)) {
            for (last_menu = menu->list; ; last_menu = last_menu->next) {
                last_menu->parent = parent;
                if (!last_menu->next) {
                    break;
                }
            }
            last_menu->next = menu->next;
            menu->next = menu->list;
            menu->list = NULL;
        }
    }

    if (sym && !(sym->flags & SYMBOL_WARNED)) {
        if (sym->type == S_UNKNOWN)
            menu_warn(parent, "config symbol defined "
                      "without type\n");

        if (sym_is_choice(sym) && !parent->prompt) {
            menu_warn(parent, "choice must have a prompt\n");
        }

        /* Check properties connected to this symbol */
        sym_check_prop(sym);
        sym->flags |= SYMBOL_WARNED;
    }

    if (sym && !sym_is_optional(sym) && parent->prompt) {
        sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr,
                                          expr_alloc_and(parent->prompt->visible.expr,
                                                         expr_alloc_symbol(&symbol_mod)));
    }
}
Example #8
0
void menu_finalize(struct menu *parent)
{
	struct menu *menu, *last_menu;
	struct symbol *sym;
	struct property *prop;
	struct expr *parentdep, *basedep, *dep, *dep2, **ep;

	sym = parent->sym;
	if (parent->list) {
		/*
		 * This menu node has children. We (recursively) process them
		 * and propagate parent dependencies before moving on.
		 */

		if (sym && sym_is_choice(sym)) {
			if (sym->type == S_UNKNOWN) {
				/* find the first choice value to find out choice type */
				current_entry = parent;
				for (menu = parent->list; menu; menu = menu->next) {
					if (menu->sym && menu->sym->type != S_UNKNOWN) {
						menu_set_type(menu->sym->type);
						break;
					}
				}
			}
			/* set the type of the remaining choice values */
			for (menu = parent->list; menu; menu = menu->next) {
				current_entry = menu;
				if (menu->sym && menu->sym->type == S_UNKNOWN)
					menu_set_type(sym->type);
			}

			/*
			 * Use the choice itself as the parent dependency of
			 * the contained items. This turns the mode of the
			 * choice into an upper bound on the visibility of the
			 * choice value symbols.
			 */
			parentdep = expr_alloc_symbol(sym);
		} else if (parent->prompt)
			/* Menu node for 'menu' */
			parentdep = parent->prompt->visible.expr;
		else
			/* Menu node for 'if' */
			parentdep = parent->dep;

		/* For each child menu node... */
		for (menu = parent->list; menu; menu = menu->next) {
			/*
			 * Propagate parent dependencies to the child menu
			 * node, also rewriting and simplifying expressions
			 */
			basedep = rewrite_m(menu->dep);
			basedep = expr_transform(basedep);
			basedep = expr_alloc_and(expr_copy(parentdep), basedep);
			basedep = expr_eliminate_dups(basedep);
			menu->dep = basedep;

			if (menu->sym)
				/*
				 * Note: For symbols, all prompts are included
				 * too in the symbol's own property list
				 */
				prop = menu->sym->prop;
			else
				/*
				 * For non-symbol menu nodes, we just need to
				 * handle the prompt
				 */
				prop = menu->prompt;

			/* For each property... */
			for (; prop; prop = prop->next) {
				if (prop->menu != menu)
					/*
					 * Two possibilities:
					 *
					 * 1. The property lacks dependencies
					 *    and so isn't location-specific,
					 *    e.g. an 'option'
					 *
					 * 2. The property belongs to a symbol
					 *    defined in multiple locations and
					 *    is from some other location. It
					 *    will be handled there in that
					 *    case.
					 *
					 * Skip the property.
					 */
					continue;

				/*
				 * Propagate parent dependencies to the
				 * property's condition, rewriting and
				 * simplifying expressions at the same time
				 */
				dep = rewrite_m(prop->visible.expr);
				dep = expr_transform(dep);
				dep = expr_alloc_and(expr_copy(basedep), dep);
				dep = expr_eliminate_dups(dep);
				if (menu->sym && menu->sym->type != S_TRISTATE)
					dep = expr_trans_bool(dep);
				prop->visible.expr = dep;

				/*
				 * Handle selects and implies, which modify the
				 * dependencies of the selected/implied symbol
				 */
				if (prop->type == P_SELECT) {
					struct symbol *es = prop_get_symbol(prop);
					es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr,
							expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep)));
				} else if (prop->type == P_IMPLY) {
					struct symbol *es = prop_get_symbol(prop);
					es->implied.expr = expr_alloc_or(es->implied.expr,
							expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep)));
				}
			}
		}

		if (sym && sym_is_choice(sym))
			expr_free(parentdep);

		/*
		 * Recursively process children in the same fashion before
		 * moving on
		 */
		for (menu = parent->list; menu; menu = menu->next)
			menu_finalize(menu);
	} else if (sym) {
		/*
		 * Automatic submenu creation. If sym is a symbol and A, B, C,
		 * ... are consecutive items (symbols, menus, ifs, etc.) that
		 * all depend on sym, then the following menu structure is
		 * created:
		 *
		 *	sym
		 *	 +-A
		 *	 +-B
		 *	 +-C
		 *	 ...
		 *
		 * This also works recursively, giving the following structure
		 * if A is a symbol and B depends on A:
		 *
		 *	sym
		 *	 +-A
		 *	 | +-B
		 *	 +-C
		 *	 ...
		 */

		basedep = parent->prompt ? parent->prompt->visible.expr : NULL;
		basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no);
		basedep = expr_eliminate_dups(expr_transform(basedep));

		/* Examine consecutive elements after sym */
		last_menu = NULL;
		for (menu = parent->next; menu; menu = menu->next) {
			dep = menu->prompt ? menu->prompt->visible.expr : menu->dep;
			if (!expr_contains_symbol(dep, sym))
				/* No dependency, quit */
				break;
			if (expr_depends_symbol(dep, sym))
				/* Absolute dependency, put in submenu */
				goto next;

			/*
			 * Also consider it a dependency on sym if our
			 * dependencies contain sym and are a "superset" of
			 * sym's dependencies, e.g. '(sym || Q) && R' when sym
			 * depends on R.
			 *
			 * Note that 'R' might be from an enclosing menu or if,
			 * making this a more common case than it might seem.
			 */
			dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no);
			dep = expr_eliminate_dups(expr_transform(dep));
			dep2 = expr_copy(basedep);
			expr_eliminate_eq(&dep, &dep2);
			expr_free(dep);
			if (!expr_is_yes(dep2)) {
				/* Not superset, quit */
				expr_free(dep2);
				break;
			}
			/* Superset, put in submenu */
			expr_free(dep2);
		next:
			menu_finalize(menu);
			menu->parent = parent;
			last_menu = menu;
		}
		expr_free(basedep);
		if (last_menu) {
			parent->list = parent->next;
			parent->next = last_menu->next;
			last_menu->next = NULL;
		}

		sym->dir_dep.expr = expr_alloc_or(sym->dir_dep.expr, parent->dep);
	}
	for (menu = parent->list; menu; menu = menu->next) {
		if (sym && sym_is_choice(sym) &&
		    menu->sym && !sym_is_choice_value(menu->sym)) {
			current_entry = menu;
			menu->sym->flags |= SYMBOL_CHOICEVAL;
			if (!menu->prompt)
				menu_warn(menu, "choice value must have a prompt");
			for (prop = menu->sym->prop; prop; prop = prop->next) {
				if (prop->type == P_DEFAULT)
					prop_warn(prop, "defaults for choice "
						  "values not supported");
				if (prop->menu == menu)
					continue;
				if (prop->type == P_PROMPT &&
				    prop->menu->parent->sym != sym)
					prop_warn(prop, "choice value used outside its choice group");
			}
			/* Non-tristate choice values of tristate choices must
			 * depend on the choice being set to Y. The choice
			 * values' dependencies were propagated to their
			 * properties above, so the change here must be re-
			 * propagated.
			 */
			if (sym->type == S_TRISTATE && menu->sym->type != S_TRISTATE) {
				basedep = expr_alloc_comp(E_EQUAL, sym, &symbol_yes);
				menu->dep = expr_alloc_and(basedep, menu->dep);
				for (prop = menu->sym->prop; prop; prop = prop->next) {
					if (prop->menu != menu)
						continue;
					prop->visible.expr = expr_alloc_and(expr_copy(basedep),
									    prop->visible.expr);
				}
			}
			menu_add_symbol(P_CHOICE, sym, NULL);
			prop = sym_get_choice_prop(sym);
			for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr)
				;
			*ep = expr_alloc_one(E_LIST, NULL);
			(*ep)->right.sym = menu->sym;
		}

		/*
		 * This code serves two purposes:
		 *
		 * (1) Flattening 'if' blocks, which do not specify a submenu
		 *     and only add dependencies.
		 *
		 *     (Automatic submenu creation might still create a submenu
		 *     from an 'if' before this code runs.)
		 *
		 * (2) "Undoing" any automatic submenus created earlier below
		 *     promptless symbols.
		 *
		 * Before:
		 *
		 *	A
		 *	if ... (or promptless symbol)
		 *	 +-B
		 *	 +-C
		 *	D
		 *
		 * After:
		 *
		 *	A
		 *	if ... (or promptless symbol)
		 *	B
		 *	C
		 *	D
		 */
		if (menu->list && (!menu->prompt || !menu->prompt->text)) {
			for (last_menu = menu->list; ; last_menu = last_menu->next) {
				last_menu->parent = parent;
				if (!last_menu->next)
					break;
			}
			last_menu->next = menu->next;
			menu->next = menu->list;
			menu->list = NULL;
		}
	}

	if (sym && !(sym->flags & SYMBOL_WARNED)) {
		if (sym->type == S_UNKNOWN)
			menu_warn(parent, "config symbol defined without type");

		if (sym_is_choice(sym) && !parent->prompt)
			menu_warn(parent, "choice must have a prompt");

		/* Check properties connected to this symbol */
		sym_check_prop(sym);
		sym->flags |= SYMBOL_WARNED;
	}

	/*
	 * For non-optional choices, add a reverse dependency (corresponding to
	 * a select) of '<visibility> && m'. This prevents the user from
	 * setting the choice mode to 'n' when the choice is visible.
	 *
	 * This would also work for non-choice symbols, but only non-optional
	 * choices clear SYMBOL_OPTIONAL as of writing. Choices are implemented
	 * as a type of symbol.
	 */
	if (sym && !sym_is_optional(sym) && parent->prompt) {
		sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr,
				expr_alloc_and(parent->prompt->visible.expr,
					expr_alloc_symbol(&symbol_mod)));
	}
}
Example #9
0
static void sym_check_prop(struct symbol *sym)
{
	struct property *prop;
	struct symbol *sym2;
	char *use;

	for (prop = sym->prop; prop; prop = prop->next) {
		switch (prop->type) {
		case P_DEFAULT:
			if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) &&
			    prop->expr->type != E_SYMBOL)
				prop_warn(prop,
				    "default for config symbol '%s'"
				    " must be a single symbol", sym->name);
			if (prop->expr->type != E_SYMBOL)
				break;
			sym2 = prop_get_symbol(prop);
			if (sym->type == S_HEX || sym->type == S_INT) {
				if (!menu_validate_number(sym, sym2))
					prop_warn(prop,
					    "'%s': number is invalid",
					    sym->name);
			}
			if (sym_is_choice(sym)) {
				struct property *choice_prop =
					sym_get_choice_prop(sym2);

				if (!choice_prop ||
				    prop_get_symbol(choice_prop) != sym)
					prop_warn(prop,
						  "choice default symbol '%s' is not contained in the choice",
						  sym2->name);
			}
			break;
		case P_SELECT:
		case P_IMPLY:
			use = prop->type == P_SELECT ? "select" : "imply";
			sym2 = prop_get_symbol(prop);
			if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE)
				prop_warn(prop,
				    "config symbol '%s' uses %s, but is "
				    "not bool or tristate", sym->name, use);
			else if (sym2->type != S_UNKNOWN &&
				 sym2->type != S_BOOLEAN &&
				 sym2->type != S_TRISTATE)
				prop_warn(prop,
				    "'%s' has wrong type. '%s' only "
				    "accept arguments of bool and "
				    "tristate type", sym2->name, use);
			break;
		case P_RANGE:
			if (sym->type != S_INT && sym->type != S_HEX)
				prop_warn(prop, "range is only allowed "
						"for int or hex symbols");
			if (!menu_validate_number(sym, prop->expr->left.sym) ||
			    !menu_validate_number(sym, prop->expr->right.sym))
				prop_warn(prop, "range is invalid");
			break;
		default:
			;
		}
	}
}