Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

kconfig: refactor choice value calculation

Handling choices has always been in a PITA in Kconfig.

For example, fixes and reverts were repeated for randconfig with
KCONFIG_ALLCONFIG:

- 422c809f03f0 ("kconfig: fix randomising choice entries in presence of KCONFIG_ALLCONFIG")
- 23a5dfdad22a ("Revert "kconfig: fix randomising choice entries in presence of KCONFIG_ALLCONFIG"")
- 8357b48549e1 ("kconfig: fix randomising choice entries in presence of KCONFIG_ALLCONFIG")
- 490f16171119 ("Revert "kconfig: fix randomising choice entries in presence of KCONFIG_ALLCONFIG"")

As these commits pointed out, randconfig does not randomize choices when
KCONFIG_ALLCONFIG is used. This issue still remains.

[Test Case]

choice
prompt "choose"

config A
bool "A"

config B
bool "B"

endchoice

$ echo > all.config
$ make KCONFIG_ALLCONFIG=1 randconfig

The output is always as follows:

CONFIG_A=y
# CONFIG_B is not set

Not only randconfig, but other all*config variants are also broken with
KCONFIG_ALLCONFIG.

With the same Kconfig,

$ echo '# CONFIG_A is not set' > all.config
$ make KCONFIG_ALLCONFIG=1 allyesconfig

You will get this:

CONFIG_A=y
# CONFIG_B is not set

This is incorrect because it does not respect all.config.

The correct output should be:

# CONFIG_A is not set
CONFIG_B=y

To handle user inputs more accurately, this commit refactors the code
based on the following principles:

- When a user value is given, Kconfig must set it immediately.
Do not defer it by setting SYMBOL_NEED_SET_CHOICE_VALUES.

- The SYMBOL_DEF_USER flag must not be cleared, unless a new config
file is loaded. Kconfig must not forget user inputs.

In addition, user values for choices must be managed with priority.
If user inputs conflict within a choice block, the newest value wins.
The values given by randconfig have lower priority than explicit user
inputs.

This commit implements it by using a linked list. Every time a choice
block gets a new input, it is moved to the top of the list.

Let me explain how it works.

Let's say, we have a choice block that consists of five symbols:
A, B, C, D, and E.

Initially, the linked list looks like this:

A(=?) --> B(=?) --> C(=?) --> D(=?) --> E(=?)

Suppose randconfig is executed with the following KCONFIG_ALLCONFIG:

CONFIG_C=y
# CONFIG_A is not set
CONFIG_D=y

First, CONFIG_C=y is read. C is set to 'y' and moved to the top.

C(=y) --> A(=?) --> B(=?) --> D(=?) --> E(=?)

Next, '# CONFIG_A is not set' is read. A is set to 'n' and moved to
the top.

A(=n) --> C(=y) --> B(=?) --> D(=?) --> E(=?)

Then, 'CONFIG_D=y' is read. D is set to 'y' and moved to the top.

D(=y) --> A(=n) --> C(=y) --> B(=?) --> E(=?)

Lastly, randconfig shuffles the order of the remaining symbols,
resulting in:

D(=y) --> A(=n) --> C(=y) --> B(=y) --> E(=y)
or
D(=y) --> A(=n) --> C(=y) --> E(=y) --> B(=y)

When calculating the output, the linked list is traversed and the first
visible symbol with 'y' is taken. In this case, it is D if visible.

If D is hidden by 'depends on', the next node, A, is examined. Since
it is already specified as 'n', it is skipped. Next, C is checked, and
selected if it is visible.

If C is also invisible, either B or E is chosen as a result of the
randomization.

If B and E are also invisible, the linked list is traversed in the
reverse order, and the least prioritized 'n' symbol is chosen. It is
A in this case.

Now, Kconfig remembers all user values. This is a big difference from
the previous implementation, where Kconfig would forget CONFIG_C=y when
CONFIG_D=y appeared in the same input file.

The new appaorch respects user-specified values as much as possible.

Signed-off-by: Masahiro Yamada <masahiroy@kernel.org>

+187 -197
+62 -69
scripts/kconfig/conf.c
··· 114 114 srand(seed); 115 115 } 116 116 117 - static void randomize_choice_values(struct symbol *csym) 117 + /** 118 + * randomize_choice_values - randomize choice block 119 + * 120 + * @choice: menu entry for the choice 121 + */ 122 + static void randomize_choice_values(struct menu *choice) 118 123 { 119 - struct property *prop; 120 - struct symbol *sym; 121 - struct expr *e; 122 - int cnt, def; 123 - 124 - prop = sym_get_choice_prop(csym); 125 - 126 - /* count entries in choice block */ 127 - cnt = 0; 128 - expr_list_for_each_sym(prop->expr, e, sym) 129 - cnt++; 124 + struct menu *menu; 125 + int x; 126 + int cnt = 0; 130 127 131 128 /* 132 - * find a random value and set it to yes, 133 - * set the rest to no so we have only one set 129 + * First, count the number of symbols to randomize. If sym_has_value() 130 + * is true, it was specified by KCONFIG_ALLCONFIG. It needs to be 131 + * respected. 134 132 */ 135 - def = rand() % cnt; 133 + menu_for_each_sub_entry(menu, choice) { 134 + struct symbol *sym = menu->sym; 136 135 137 - cnt = 0; 138 - expr_list_for_each_sym(prop->expr, e, sym) { 139 - if (def == cnt++) { 140 - sym->def[S_DEF_USER].tri = yes; 141 - csym->def[S_DEF_USER].val = sym; 142 - } else { 143 - sym->def[S_DEF_USER].tri = no; 144 - } 145 - sym->flags |= SYMBOL_DEF_USER; 146 - /* clear VALID to get value calculated */ 147 - sym->flags &= ~SYMBOL_VALID; 136 + if (sym && !sym_has_value(sym)) 137 + cnt++; 148 138 } 149 - csym->flags |= SYMBOL_DEF_USER; 150 - /* clear VALID to get value calculated */ 151 - csym->flags &= ~SYMBOL_VALID; 139 + 140 + while (cnt > 0) { 141 + x = rand() % cnt; 142 + 143 + menu_for_each_sub_entry(menu, choice) { 144 + struct symbol *sym = menu->sym; 145 + 146 + if (sym && !sym_has_value(sym)) 147 + x--; 148 + 149 + if (x < 0) { 150 + sym->def[S_DEF_USER].tri = yes; 151 + sym->flags |= SYMBOL_DEF_USER; 152 + /* 153 + * Move the selected item to the _tail_ because 154 + * this needs to have a lower priority than the 155 + * user input from KCONFIG_ALLCONFIG. 156 + */ 157 + list_move_tail(&sym->choice_link, 158 + &choice->choice_members); 159 + 160 + break; 161 + } 162 + } 163 + cnt--; 164 + } 152 165 } 153 166 154 167 enum conf_def_mode { ··· 172 159 def_random 173 160 }; 174 161 175 - static bool conf_set_all_new_symbols(enum conf_def_mode mode) 162 + static void conf_set_all_new_symbols(enum conf_def_mode mode) 176 163 { 177 - struct symbol *sym, *csym; 164 + struct menu *menu; 178 165 int cnt; 179 166 /* 180 167 * can't go as the default in switch-case below, otherwise gcc whines ··· 183 170 int pby = 50; /* probability of bool = y */ 184 171 int pty = 33; /* probability of tristate = y */ 185 172 int ptm = 33; /* probability of tristate = m */ 186 - bool has_changed = false; 187 173 188 174 if (mode == def_random) { 189 175 int n, p[3]; ··· 229 217 } 230 218 } 231 219 232 - for_all_symbols(sym) { 220 + menu_for_each_entry(menu) { 221 + struct symbol *sym = menu->sym; 233 222 tristate val; 234 223 235 - if (sym_has_value(sym) || sym->flags & SYMBOL_VALID || 236 - (sym->type != S_BOOLEAN && sym->type != S_TRISTATE)) 224 + if (!sym || !menu->prompt || sym_has_value(sym) || 225 + (sym->type != S_BOOLEAN && sym->type != S_TRISTATE) || 226 + sym_is_choice_value(sym)) 237 227 continue; 238 228 239 - has_changed = true; 229 + if (sym_is_choice(sym)) { 230 + if (mode == def_random) 231 + randomize_choice_values(menu); 232 + continue; 233 + } 234 + 240 235 switch (mode) { 241 236 case def_yes: 242 237 val = yes; ··· 270 251 continue; 271 252 } 272 253 sym->def[S_DEF_USER].tri = val; 273 - 274 - if (!(sym_is_choice(sym) && mode == def_random)) 275 - sym->flags |= SYMBOL_DEF_USER; 254 + sym->flags |= SYMBOL_DEF_USER; 276 255 } 277 256 278 257 sym_clear_all_valid(); 279 - 280 - if (mode != def_random) { 281 - for_all_symbols(csym) { 282 - if ((sym_is_choice(csym) && !sym_has_value(csym)) || 283 - sym_is_choice_value(csym)) 284 - csym->flags |= SYMBOL_NEED_SET_CHOICE_VALUES; 285 - } 286 - } 287 - 288 - for_all_symbols(csym) { 289 - if (sym_has_value(csym) || !sym_is_choice(csym)) 290 - continue; 291 - 292 - sym_calc_value(csym); 293 - if (mode == def_random) 294 - randomize_choice_values(csym); 295 - else 296 - set_all_choice_values(csym); 297 - has_changed = true; 298 - } 299 - 300 - return has_changed; 301 258 } 302 259 303 260 static void conf_rewrite_tristates(tristate old_val, tristate new_val) ··· 424 429 { 425 430 struct symbol *sym, *def_sym; 426 431 struct menu *child; 427 - bool is_new; 432 + bool is_new = false; 428 433 429 434 sym = menu->sym; 430 - is_new = !sym_has_value(sym); 431 435 432 436 while (1) { 433 437 int cnt, def; ··· 450 456 printf("%*c", indent, ' '); 451 457 printf(" %d. %s (%s)", cnt, menu_get_prompt(child), 452 458 child->sym->name); 453 - if (!sym_has_value(child->sym)) 459 + if (!sym_has_value(child->sym)) { 460 + is_new = true; 454 461 printf(" (NEW)"); 462 + } 455 463 printf("\n"); 456 464 } 457 465 printf("%*schoice", indent - 1, ""); ··· 582 586 return; 583 587 584 588 sym = menu->sym; 585 - if (sym && !sym_has_value(sym) && 586 - (sym_is_changeable(sym) || sym_is_choice(sym))) { 587 - 589 + if (sym && !sym_has_value(sym) && sym_is_changeable(sym)) { 588 590 switch (input_mode) { 589 591 case listnewconfig: 590 592 if (sym->name) ··· 798 804 conf_set_all_new_symbols(def_default); 799 805 break; 800 806 case randconfig: 801 - /* Really nothing to do in this loop */ 802 - while (conf_set_all_new_symbols(def_random)) ; 807 + conf_set_all_new_symbols(def_random); 803 808 break; 804 809 case defconfig: 805 810 conf_set_all_new_symbols(def_default);
+10 -44
scripts/kconfig/confdata.c
··· 382 382 383 383 def_flags = SYMBOL_DEF << def; 384 384 for_all_symbols(sym) { 385 - sym->flags |= SYMBOL_CHANGED; 386 385 sym->flags &= ~(def_flags|SYMBOL_VALID); 387 - if (sym_is_choice(sym)) 388 - sym->flags |= def_flags; 389 386 switch (sym->type) { 390 387 case S_INT: 391 388 case S_HEX: ··· 396 399 } 397 400 398 401 while (getline_stripped(&line, &line_asize, in) != -1) { 402 + struct menu *choice; 403 + 399 404 conf_lineno++; 400 405 401 406 if (!line[0]) /* blank line */ ··· 459 460 if (conf_set_sym_val(sym, def, def_flags, val)) 460 461 continue; 461 462 462 - if (sym && sym_is_choice_value(sym)) { 463 - struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym)); 464 - if (sym->def[def].tri == yes) { 465 - if (cs->def[def].tri != no) 466 - conf_warning("override: %s changes choice state", sym->name); 467 - cs->def[def].val = sym; 468 - cs->def[def].tri = yes; 469 - } 470 - } 463 + /* 464 + * If this is a choice member, give it the highest priority. 465 + * If conflicting CONFIG options are given from an input file, 466 + * the last one wins. 467 + */ 468 + choice = sym_get_choice_menu(sym); 469 + if (choice) 470 + list_move(&sym->choice_link, &choice->choice_members); 471 471 } 472 472 free(line); 473 473 fclose(in); ··· 510 512 continue; 511 513 conf_unsaved++; 512 514 /* maybe print value in verbose mode... */ 513 - } 514 - 515 - for_all_symbols(sym) { 516 - if (sym_has_value(sym) && !sym_is_choice_value(sym)) { 517 - /* Reset values of generates values, so they'll appear 518 - * as new, if they should become visible, but that 519 - * doesn't quite work if the Kconfig and the saved 520 - * configuration disagree. 521 - */ 522 - if (sym->visible == no && !conf_unsaved) 523 - sym->flags &= ~SYMBOL_DEF_USER; 524 - } 525 515 } 526 516 527 517 if (conf_warnings || conf_unsaved) ··· 1131 1145 void conf_set_changed_callback(void (*fn)(bool)) 1132 1146 { 1133 1147 conf_changed_callback = fn; 1134 - } 1135 - 1136 - void set_all_choice_values(struct symbol *csym) 1137 - { 1138 - struct property *prop; 1139 - struct symbol *sym; 1140 - struct expr *e; 1141 - 1142 - prop = sym_get_choice_prop(csym); 1143 - 1144 - /* 1145 - * Set all non-assinged choice values to no 1146 - */ 1147 - expr_list_for_each_sym(prop->expr, e, sym) { 1148 - if (!sym_has_value(sym)) 1149 - sym->def[S_DEF_USER].tri = no; 1150 - } 1151 - csym->flags |= SYMBOL_DEF_USER; 1152 - /* clear VALID to get value calculated */ 1153 - csym->flags &= ~(SYMBOL_VALID | SYMBOL_NEED_SET_CHOICE_VALUES); 1154 1148 }
+8 -4
scripts/kconfig/expr.h
··· 73 73 * Represents a configuration symbol. 74 74 * 75 75 * Choices are represented as a special kind of symbol with null name. 76 + * 77 + * @choice_link: linked to menu::choice_members 76 78 */ 77 79 struct symbol { 78 80 /* link node for the hash table */ ··· 112 110 /* config entries associated with this symbol */ 113 111 struct list_head menus; 114 112 113 + struct list_head choice_link; 114 + 115 115 /* SYMBOL_* flags */ 116 116 int flags; 117 117 ··· 137 133 #define SYMBOL_CHOICEVAL 0x0020 /* used as a value in a choice block */ 138 134 #define SYMBOL_VALID 0x0080 /* set when symbol.curr is calculated */ 139 135 #define SYMBOL_WRITE 0x0200 /* write symbol to file (KCONFIG_CONFIG) */ 140 - #define SYMBOL_CHANGED 0x0400 /* ? */ 141 136 #define SYMBOL_WRITTEN 0x0800 /* track info to avoid double-write to .config */ 142 137 #define SYMBOL_CHECKED 0x2000 /* used during dependency checking */ 143 138 #define SYMBOL_WARNED 0x8000 /* warning has been issued */ ··· 147 144 #define SYMBOL_DEF_AUTO 0x20000 /* symbol.def[S_DEF_AUTO] is valid */ 148 145 #define SYMBOL_DEF3 0x40000 /* symbol.def[S_DEF_3] is valid */ 149 146 #define SYMBOL_DEF4 0x80000 /* symbol.def[S_DEF_4] is valid */ 150 - 151 - /* choice values need to be set before calculating this symbol value */ 152 - #define SYMBOL_NEED_SET_CHOICE_VALUES 0x100000 153 147 154 148 #define SYMBOL_MAXLENGTH 256 155 149 ··· 204 204 * for all front ends). Each symbol, menu, etc. defined in the Kconfig files 205 205 * gets a node. A symbol defined in multiple locations gets one node at each 206 206 * location. 207 + * 208 + * @choice_members: list of choice members with priority. 207 209 */ 208 210 struct menu { 209 211 /* The next menu node at the same level */ ··· 224 222 struct symbol *sym; 225 223 226 224 struct list_head link; /* link to symbol::menus */ 225 + 226 + struct list_head choice_members; 227 227 228 228 /* 229 229 * The prompt associated with the node. This holds the prompt for a
+1 -6
scripts/kconfig/lkc.h
··· 40 40 /* confdata.c */ 41 41 extern struct gstr autoconf_cmd; 42 42 const char *conf_get_configname(void); 43 - void set_all_choice_values(struct symbol *csym); 44 43 45 44 /* confdata.c and expr.c */ 46 45 static inline void xfwrite(const void *str, size_t len, size_t count, FILE *out) ··· 120 121 return sym->curr.tri; 121 122 } 122 123 123 - 124 - static inline struct symbol *sym_get_choice_value(struct symbol *sym) 125 - { 126 - return (struct symbol *)sym->curr.val; 127 - } 124 + struct symbol *sym_get_choice_value(struct symbol *sym); 128 125 129 126 static inline bool sym_is_choice(struct symbol *sym) 130 127 {
+1 -16
scripts/kconfig/menu.c
··· 591 591 592 592 bool menu_is_visible(struct menu *menu) 593 593 { 594 - struct menu *child; 595 594 struct symbol *sym; 596 595 tristate visible; 597 596 ··· 609 610 } else 610 611 visible = menu->prompt->visible.tri = expr_calc_value(menu->prompt->visible.expr); 611 612 612 - if (visible != no) 613 - return true; 614 - 615 - if (!sym || sym_get_tristate_value(menu->sym) == no) 616 - return false; 617 - 618 - for (child = menu->list; child; child = child->next) { 619 - if (menu_is_visible(child)) { 620 - if (sym) 621 - sym->flags |= SYMBOL_DEF_USER; 622 - return true; 623 - } 624 - } 625 - 626 - return false; 613 + return visible != no; 627 614 } 628 615 629 616 const char *menu_get_prompt(struct menu *menu)
+4
scripts/kconfig/parser.y
··· 157 157 current_entry->filename, current_entry->lineno); 158 158 yynerrs++; 159 159 } 160 + 161 + list_add_tail(&current_entry->sym->choice_link, 162 + &current_choice->choice_members); 160 163 } 161 164 162 165 printd(DEBUG_PARSE, "%s:%d:endconfig\n", cur_filename, cur_lineno); ··· 243 240 menu_add_entry(sym); 244 241 menu_add_expr(P_CHOICE, NULL, NULL); 245 242 menu_set_type(S_BOOLEAN); 243 + INIT_LIST_HEAD(&current_entry->choice_members); 246 244 247 245 printd(DEBUG_PARSE, "%s:%d:choice\n", cur_filename, cur_lineno); 248 246 };
+101 -58
scripts/kconfig/symbol.c
··· 188 188 { 189 189 struct menu *menu; 190 190 191 - sym->flags |= SYMBOL_CHANGED; 192 191 list_for_each_entry(menu, &sym->menus, link) 193 192 menu->flags |= MENU_CHANGED; 194 193 } ··· 281 282 return NULL; 282 283 } 283 284 284 - static struct symbol *sym_calc_choice(struct symbol *sym) 285 + /* 286 + * sym_calc_choice - calculate symbol values in a choice 287 + * 288 + * @choice: a menu of the choice 289 + * 290 + * Return: a chosen symbol 291 + */ 292 + static struct symbol *sym_calc_choice(struct menu *choice) 285 293 { 286 - struct symbol *def_sym; 287 - struct property *prop; 288 - struct expr *e; 289 - int flags; 294 + struct symbol *res = NULL; 295 + struct symbol *sym; 296 + struct menu *menu; 290 297 291 - /* first calculate all choice values' visibilities */ 292 - flags = sym->flags; 293 - prop = sym_get_choice_prop(sym); 294 - expr_list_for_each_sym(prop->expr, e, def_sym) { 295 - sym_calc_visibility(def_sym); 296 - if (def_sym->visible != no) 297 - flags &= def_sym->flags; 298 + /* Traverse the list of choice members in the priority order. */ 299 + list_for_each_entry(sym, &choice->choice_members, choice_link) { 300 + sym_calc_visibility(sym); 301 + if (sym->visible == no) 302 + continue; 303 + 304 + /* The first visible symble with the user value 'y'. */ 305 + if (sym_has_value(sym) && sym->def[S_DEF_USER].tri == yes) { 306 + res = sym; 307 + break; 308 + } 298 309 } 299 310 300 - sym->flags &= flags | ~SYMBOL_DEF_USER; 311 + /* 312 + * If 'y' is not found in the user input, use the default, unless it is 313 + * explicitly set to 'n'. 314 + */ 315 + if (!res) { 316 + res = sym_choice_default(choice->sym); 317 + if (res && sym_has_value(res) && res->def[S_DEF_USER].tri == no) 318 + res = NULL; 319 + } 301 320 302 - /* is the user choice visible? */ 303 - def_sym = sym->def[S_DEF_USER].val; 304 - if (def_sym && def_sym->visible != no) 305 - return def_sym; 321 + /* Still not found. Pick up the first visible, user-unspecified symbol. */ 322 + if (!res) { 323 + menu_for_each_sub_entry(menu, choice) { 324 + sym = menu->sym; 306 325 307 - def_sym = sym_choice_default(sym); 326 + if (!sym || sym->visible == no || sym_has_value(sym)) 327 + continue; 308 328 309 - if (def_sym == NULL) 310 - /* no choice? reset tristate value */ 311 - sym->curr.tri = no; 329 + res = sym; 330 + break; 331 + } 332 + } 312 333 313 - return def_sym; 334 + /* 335 + * Still not found. Traverse the linked list in the _reverse_ order to 336 + * pick up the least prioritized 'n'. 337 + */ 338 + if (!res) { 339 + list_for_each_entry_reverse(sym, &choice->choice_members, 340 + choice_link) { 341 + if (sym->visible == no) 342 + continue; 343 + 344 + res = sym; 345 + break; 346 + } 347 + } 348 + 349 + menu_for_each_sub_entry(menu, choice) { 350 + tristate val; 351 + 352 + sym = menu->sym; 353 + 354 + if (!sym || sym->visible == no) 355 + continue; 356 + 357 + val = sym == res ? yes : no; 358 + 359 + if (sym->curr.tri != val) 360 + sym_set_changed(sym); 361 + 362 + sym->curr.tri = val; 363 + sym->flags |= SYMBOL_VALID | SYMBOL_WRITE; 364 + } 365 + 366 + return res; 367 + } 368 + 369 + struct symbol *sym_get_choice_value(struct symbol *sym) 370 + { 371 + struct menu *menu = list_first_entry(&sym->menus, struct menu, link); 372 + 373 + return sym_calc_choice(menu); 314 374 } 315 375 316 376 static void sym_warn_unmet_dep(struct symbol *sym) ··· 405 347 { 406 348 struct symbol_value newval, oldval; 407 349 struct property *prop; 408 - struct expr *e; 350 + struct menu *choice_menu; 409 351 410 352 if (!sym) 411 353 return; 412 354 413 355 if (sym->flags & SYMBOL_VALID) 414 356 return; 415 - 416 - if (sym_is_choice_value(sym) && 417 - sym->flags & SYMBOL_NEED_SET_CHOICE_VALUES) { 418 - sym->flags &= ~SYMBOL_NEED_SET_CHOICE_VALUES; 419 - prop = sym_get_choice_prop(sym); 420 - sym_calc_value(prop_get_symbol(prop)); 421 - } 422 357 423 358 sym->flags |= SYMBOL_VALID; 424 359 ··· 451 400 switch (sym_get_type(sym)) { 452 401 case S_BOOLEAN: 453 402 case S_TRISTATE: 454 - if (sym_is_choice_value(sym) && sym->visible == yes) { 455 - prop = sym_get_choice_prop(sym); 456 - newval.tri = (prop_get_symbol(prop)->curr.val == sym) ? yes : no; 403 + choice_menu = sym_get_choice_menu(sym); 404 + 405 + if (choice_menu) { 406 + sym_calc_choice(choice_menu); 407 + newval.tri = sym->curr.tri; 457 408 } else { 458 409 if (sym->visible != no) { 459 410 /* if the symbol is visible use the user value ··· 514 461 } 515 462 516 463 sym->curr = newval; 517 - if (sym_is_choice(sym) && newval.tri == yes) 518 - sym->curr.val = sym_calc_choice(sym); 519 464 sym_validate_range(sym); 520 465 521 466 if (memcmp(&oldval, &sym->curr, sizeof(oldval))) { ··· 524 473 } 525 474 } 526 475 527 - if (sym_is_choice(sym)) { 528 - struct symbol *choice_sym; 529 - 530 - prop = sym_get_choice_prop(sym); 531 - expr_list_for_each_sym(prop->expr, e, choice_sym) { 532 - if ((sym->flags & SYMBOL_WRITE) && 533 - choice_sym->visible != no) 534 - choice_sym->flags |= SYMBOL_WRITE; 535 - if (sym->flags & SYMBOL_CHANGED) 536 - sym_set_changed(choice_sym); 537 - } 538 - 476 + if (sym_is_choice(sym)) 539 477 sym->flags &= ~SYMBOL_WRITE; 540 - } 541 - 542 - if (sym->flags & SYMBOL_NEED_SET_CHOICE_VALUES) 543 - set_all_choice_values(sym); 544 478 } 545 479 546 480 void sym_clear_all_valid(void) ··· 559 523 { 560 524 tristate oldval = sym_get_tristate_value(sym); 561 525 562 - if (oldval != val && !sym_tristate_within_range(sym, val)) 526 + if (!sym_tristate_within_range(sym, val)) 563 527 return false; 564 528 565 - if (!(sym->flags & SYMBOL_DEF_USER)) { 529 + if (!(sym->flags & SYMBOL_DEF_USER) || sym->def[S_DEF_USER].tri != val) { 530 + sym->def[S_DEF_USER].tri = val; 566 531 sym->flags |= SYMBOL_DEF_USER; 567 532 sym_set_changed(sym); 568 533 } 569 534 570 - sym->def[S_DEF_USER].tri = val; 571 535 if (oldval != val) 572 536 sym_clear_all_valid(); 573 537 ··· 601 565 602 566 menu->sym->def[S_DEF_USER].tri = val; 603 567 menu->sym->flags |= SYMBOL_DEF_USER; 604 - } 605 568 606 - choice->sym->def[S_DEF_USER].val = sym; 607 - choice->sym->flags |= SYMBOL_DEF_USER; 569 + /* 570 + * Now, the user has explicitly enabled or disabled this symbol, 571 + * it should be given the highest priority. We are possibly 572 + * setting multiple symbols to 'n', where the first symbol is 573 + * given the least prioritized 'n'. This works well when the 574 + * choice block ends up with selecting 'n' symbol. 575 + * (see sym_calc_choice()) 576 + */ 577 + list_move(&menu->sym->choice_link, &choice->choice_members); 578 + } 608 579 609 580 if (changed) 610 581 sym_clear_all_valid();