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 <ctype.h> 7#include <stdlib.h> 8#include <string.h> 9#include <sys/utsname.h> 10 11#define LKC_DIRECT_LINK 12#include "lkc.h" 13 14struct symbol symbol_yes = { 15 name: "y", 16 curr: { "y", yes }, 17 flags: SYMBOL_YES|SYMBOL_VALID, 18}, symbol_mod = { 19 name: "m", 20 curr: { "m", mod }, 21 flags: SYMBOL_MOD|SYMBOL_VALID, 22}, symbol_no = { 23 name: "n", 24 curr: { "n", no }, 25 flags: SYMBOL_NO|SYMBOL_VALID, 26}, symbol_empty = { 27 name: "", 28 curr: { "", no }, 29 flags: SYMBOL_VALID, 30}; 31 32int sym_change_count; 33struct symbol *modules_sym; 34 35void sym_add_default(struct symbol *sym, const char *def) 36{ 37 struct property *prop = create_prop(P_DEFAULT); 38 struct property **propp; 39 40 prop->sym = sym; 41 prop->def = sym_lookup(def, 1); 42 43 /* append property to the prop list of symbol */ 44 if (prop->sym) { 45 for (propp = &prop->sym->prop; *propp; propp = &(*propp)->next) 46 ; 47 *propp = prop; 48 } 49} 50 51void sym_init(void) 52{ 53 struct symbol *sym; 54 struct utsname uts; 55 char *p; 56 static bool inited = false; 57 58 if (inited) 59 return; 60 inited = true; 61 62 uname(&uts); 63 64 65 sym = sym_lookup("VERSION", 0); 66 sym->type = S_STRING; 67 sym->flags |= SYMBOL_AUTO; 68 p = getenv("VERSION"); 69 if (p) 70 sym_add_default(sym, p); 71 72 73 sym = sym_lookup("TARGET_ARCH", 0); 74 sym->type = S_STRING; 75 sym->flags |= SYMBOL_AUTO; 76 p = getenv("TARGET_ARCH"); 77 if (p) 78 sym_add_default(sym, p); 79} 80 81int sym_get_type(struct symbol *sym) 82{ 83 int type = sym->type; 84 if (type == S_TRISTATE) { 85 if (sym_is_choice_value(sym) && sym->visible == yes) 86 type = S_BOOLEAN; 87 else { 88 sym_calc_value(modules_sym); 89 if (S_TRI(modules_sym->curr) == no) 90 type = S_BOOLEAN; 91 } 92 } 93 return type; 94} 95 96const char *sym_type_name(int type) 97{ 98 switch (type) { 99 case S_BOOLEAN: 100 return "boolean"; 101 case S_TRISTATE: 102 return "tristate"; 103 case S_INT: 104 return "integer"; 105 case S_HEX: 106 return "hex"; 107 case S_STRING: 108 return "string"; 109 case S_UNKNOWN: 110 return "unknown"; 111 } 112 return "???"; 113} 114 115struct property *sym_get_choice_prop(struct symbol *sym) 116{ 117 struct property *prop; 118 119 for_all_choices(sym, prop) 120 return prop; 121 return NULL; 122} 123 124struct property *sym_get_default_prop(struct symbol *sym) 125{ 126 struct property *prop; 127 tristate visible; 128 129 for_all_defaults(sym, prop) { 130 visible = E_CALC(prop->visible); 131 if (visible != no) 132 return prop; 133 } 134 return NULL; 135} 136 137void sym_calc_visibility(struct symbol *sym) 138{ 139 struct property *prop; 140 tristate visible, oldvisible; 141 142 /* any prompt visible? */ 143 oldvisible = sym->visible; 144 visible = no; 145 for_all_prompts(sym, prop) 146 visible = E_OR(visible, E_CALC(prop->visible)); 147 if (oldvisible != visible) { 148 sym->visible = visible; 149 sym->flags |= SYMBOL_CHANGED; 150 } 151} 152 153void sym_calc_value(struct symbol *sym) 154{ 155 struct symbol_value newval, oldval; 156 struct property *prop, *def_prop; 157 struct symbol *def_sym; 158 struct expr *e; 159 160 if (sym->flags & SYMBOL_VALID) 161 return; 162 163 oldval = sym->curr; 164 165 switch (sym->type) { 166 case S_INT: 167 case S_HEX: 168 case S_STRING: 169 newval = symbol_empty.curr; 170 break; 171 case S_BOOLEAN: 172 case S_TRISTATE: 173 newval = symbol_no.curr; 174 break; 175 default: 176 S_VAL(newval) = sym->name; 177 S_TRI(newval) = no; 178 if (sym->flags & SYMBOL_CONST) { 179 goto out; 180 } 181 //newval = symbol_empty.curr; 182 // generate warning somewhere here later 183 //S_TRI(newval) = yes; 184 goto out; 185 } 186 sym->flags |= SYMBOL_VALID; 187 if (!sym_is_choice_value(sym)) 188 sym->flags &= ~SYMBOL_WRITE; 189 190 sym_calc_visibility(sym); 191 192 /* set default if recursively called */ 193 sym->curr = newval; 194 195 if (sym->visible != no) { 196 sym->flags |= SYMBOL_WRITE; 197 if (!sym_has_value(sym)) { 198 if (!sym_is_choice(sym)) { 199 prop = sym_get_default_prop(sym); 200 if (prop) { 201 sym_calc_value(prop->def); 202 newval = prop->def->curr; 203 } 204 } 205 } else 206 newval = sym->def; 207 208 S_TRI(newval) = E_AND(S_TRI(newval), sym->visible); 209 /* if the symbol is visible and not optionial, 210 * possibly ignore old user choice. */ 211 if (!sym_is_optional(sym) && S_TRI(newval) == no) 212 S_TRI(newval) = sym->visible; 213 if (sym_is_choice_value(sym) && sym->visible == yes) { 214 prop = sym_get_choice_prop(sym); 215 S_TRI(newval) = (S_VAL(prop->def->curr) == sym) ? yes : no; 216 } 217 } else { 218 prop = sym_get_default_prop(sym); 219 if (prop) { 220 sym->flags |= SYMBOL_WRITE; 221 sym_calc_value(prop->def); 222 newval = prop->def->curr; 223 } 224 } 225 226 switch (sym_get_type(sym)) { 227 case S_TRISTATE: 228 if (S_TRI(newval) != mod) 229 break; 230 sym_calc_value(modules_sym); 231 if (S_TRI(modules_sym->curr) == no) 232 S_TRI(newval) = yes; 233 break; 234 case S_BOOLEAN: 235 if (S_TRI(newval) == mod) 236 S_TRI(newval) = yes; 237 } 238 239out: 240 sym->curr = newval; 241 242 if (sym_is_choice(sym) && S_TRI(newval) == yes) { 243 def_sym = S_VAL(sym->def); 244 if (def_sym) { 245 sym_calc_visibility(def_sym); 246 if (def_sym->visible == no) 247 def_sym = NULL; 248 } 249 if (!def_sym) { 250 for_all_defaults(sym, def_prop) { 251 if (E_CALC(def_prop->visible) == no) 252 continue; 253 sym_calc_visibility(def_prop->def); 254 if (def_prop->def->visible != no) { 255 def_sym = def_prop->def; 256 break; 257 } 258 } 259 } 260 261 if (!def_sym) { 262 prop = sym_get_choice_prop(sym); 263 for (e = prop->dep; e; e = e->left.expr) { 264 sym_calc_visibility(e->right.sym); 265 if (e->right.sym->visible != no) { 266 def_sym = e->right.sym; 267 break; 268 } 269 } 270 } 271 272 S_VAL(newval) = def_sym; 273 } 274 275 if (memcmp(&oldval, &newval, sizeof(newval))) 276 sym->flags |= SYMBOL_CHANGED; 277 sym->curr = newval; 278 279 if (sym_is_choice(sym)) { 280 int flags = sym->flags & (SYMBOL_CHANGED | SYMBOL_WRITE); 281 prop = sym_get_choice_prop(sym); 282 for (e = prop->dep; e; e = e->left.expr) 283 e->right.sym->flags |= flags; 284 } 285} 286 287void sym_clear_all_valid(void) 288{ 289 struct symbol *sym; 290 int i; 291 292 for_all_symbols(i, sym) 293 sym->flags &= ~SYMBOL_VALID; 294 sym_change_count++; 295} 296 297void sym_set_all_changed(void) 298{ 299 struct symbol *sym; 300 int i; 301 302 for_all_symbols(i, sym) 303 sym->flags |= SYMBOL_CHANGED; 304} 305 306bool sym_tristate_within_range(struct symbol *sym, tristate val) 307{ 308 int type = sym_get_type(sym); 309 310 if (sym->visible == no) 311 return false; 312 313 if (type != S_BOOLEAN && type != S_TRISTATE) 314 return false; 315 316 switch (val) { 317 case no: 318 if (sym_is_choice_value(sym) && sym->visible == yes) 319 return false; 320 return sym_is_optional(sym); 321 case mod: 322 if (sym_is_choice_value(sym) && sym->visible == yes) 323 return false; 324 return type == S_TRISTATE; 325 case yes: 326 return type == S_BOOLEAN || sym->visible == yes; 327 } 328 return false; 329} 330 331bool sym_set_tristate_value(struct symbol *sym, tristate val) 332{ 333 tristate oldval = sym_get_tristate_value(sym); 334 335 if (oldval != val && !sym_tristate_within_range(sym, val)) 336 return false; 337 338 if (sym->flags & SYMBOL_NEW) { 339 sym->flags &= ~SYMBOL_NEW; 340 sym->flags |= SYMBOL_CHANGED; 341 } 342 if (sym_is_choice_value(sym) && val == yes) { 343 struct property *prop = sym_get_choice_prop(sym); 344 345 S_VAL(prop->def->def) = sym; 346 prop->def->flags &= ~SYMBOL_NEW; 347 } 348 349 S_TRI(sym->def) = val; 350 if (oldval != val) { 351 sym_clear_all_valid(); 352 if (sym == modules_sym) 353 sym_set_all_changed(); 354 } 355 356 return true; 357} 358 359tristate sym_toggle_tristate_value(struct symbol *sym) 360{ 361 tristate oldval, newval; 362 363 oldval = newval = sym_get_tristate_value(sym); 364 do { 365 switch (newval) { 366 case no: 367 newval = mod; 368 break; 369 case mod: 370 newval = yes; 371 break; 372 case yes: 373 newval = no; 374 break; 375 } 376 if (sym_set_tristate_value(sym, newval)) 377 break; 378 } while (oldval != newval); 379 return newval; 380} 381 382bool sym_string_valid(struct symbol *sym, const char *str) 383{ 384 char ch; 385 386 switch (sym->type) { 387 case S_STRING: 388 return true; 389 case S_INT: 390 ch = *str++; 391 if (ch == '-') 392 ch = *str++; 393 if (!isdigit((int)ch)) 394 return false; 395 if (ch == '0' && *str != 0) 396 return false; 397 while ((ch = *str++)) { 398 if (!isdigit((int)ch)) 399 return false; 400 } 401 return true; 402 case S_HEX: 403 if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) 404 str += 2; 405 ch = *str++; 406 do { 407 if (!isxdigit((int)ch)) 408 return false; 409 } while ((ch = *str++)); 410 return true; 411 case S_BOOLEAN: 412 case S_TRISTATE: 413 switch (str[0]) { 414 case 'y': 415 case 'Y': 416 return sym_tristate_within_range(sym, yes); 417 case 'm': 418 case 'M': 419 return sym_tristate_within_range(sym, mod); 420 case 'n': 421 case 'N': 422 return sym_tristate_within_range(sym, no); 423 } 424 return false; 425 default: 426 return false; 427 } 428} 429 430bool sym_set_string_value(struct symbol *sym, const char *newval) 431{ 432 const char *oldval; 433 char *val; 434 int size; 435 436 switch (sym->type) { 437 case S_BOOLEAN: 438 case S_TRISTATE: 439 switch (newval[0]) { 440 case 'y': 441 case 'Y': 442 return sym_set_tristate_value(sym, yes); 443 case 'm': 444 case 'M': 445 return sym_set_tristate_value(sym, mod); 446 case 'n': 447 case 'N': 448 return sym_set_tristate_value(sym, no); 449 } 450 return false; 451 default: 452 ; 453 } 454 455 if (!sym_string_valid(sym, newval)) 456 return false; 457 458 if (sym->flags & SYMBOL_NEW) { 459 sym->flags &= ~SYMBOL_NEW; 460 sym->flags |= SYMBOL_CHANGED; 461 } 462 463 oldval = S_VAL(sym->def); 464 size = strlen(newval) + 1; 465 if (sym->type == S_HEX && (newval[0] != '0' || (newval[1] != 'x' && newval[1] != 'X'))) { 466 size += 2; 467 S_VAL(sym->def) = val = malloc(size); 468 *val++ = '0'; 469 *val++ = 'x'; 470 } else if (!oldval || strcmp(oldval, newval)) 471 S_VAL(sym->def) = val = malloc(size); 472 else 473 return true; 474 475 strcpy(val, newval); 476 free((void *)oldval); 477 sym_clear_all_valid(); 478 479 return true; 480} 481 482const char *sym_get_string_value(struct symbol *sym) 483{ 484 tristate val; 485 486 switch (sym->type) { 487 case S_BOOLEAN: 488 case S_TRISTATE: 489 val = sym_get_tristate_value(sym); 490 switch (val) { 491 case no: 492 return "n"; 493 case mod: 494 return "m"; 495 case yes: 496 return "y"; 497 } 498 break; 499 default: 500 ; 501 } 502 return (const char *)S_VAL(sym->curr); 503} 504 505bool sym_is_changable(struct symbol *sym) 506{ 507 if (sym->visible == no) 508 return false; 509 /* at least 'n' and 'y'/'m' is selectable */ 510 if (sym_is_optional(sym)) 511 return true; 512 /* no 'n', so 'y' and 'm' must be selectable */ 513 if (sym_get_type(sym) == S_TRISTATE && sym->visible == yes) 514 return true; 515 return false; 516} 517 518struct symbol *sym_lookup(const char *name, int isconst) 519{ 520 struct symbol *symbol; 521 const char *ptr; 522 char *new_name; 523 int hash = 0; 524 525 //printf("lookup: %s -> ", name); 526 if (name) { 527 if (name[0] && !name[1]) { 528 switch (name[0]) { 529 case 'y': return &symbol_yes; 530 case 'm': return &symbol_mod; 531 case 'n': return &symbol_no; 532 } 533 } 534 for (ptr = name; *ptr; ptr++) 535 hash += *ptr; 536 hash &= 0xff; 537 538 for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) { 539 if (!strcmp(symbol->name, name)) { 540 if ((isconst && symbol->flags & SYMBOL_CONST) || 541 (!isconst && !(symbol->flags & SYMBOL_CONST))) { 542 //printf("h:%p\n", symbol); 543 return symbol; 544 } 545 } 546 } 547 new_name = strdup(name); 548 } else { 549 new_name = NULL; 550 hash = 256; 551 } 552 553 symbol = malloc(sizeof(*symbol)); 554 memset(symbol, 0, sizeof(*symbol)); 555 symbol->name = new_name; 556 symbol->type = S_UNKNOWN; 557 symbol->flags = SYMBOL_NEW; 558 if (isconst) 559 symbol->flags |= SYMBOL_CONST; 560 561 symbol->next = symbol_hash[hash]; 562 symbol_hash[hash] = symbol; 563 564 //printf("n:%p\n", symbol); 565 return symbol; 566} 567 568struct symbol *sym_find(const char *name) 569{ 570 struct symbol *symbol = NULL; 571 const char *ptr; 572 int hash = 0; 573 574 if (!name) 575 return NULL; 576 577 if (name[0] && !name[1]) { 578 switch (name[0]) { 579 case 'y': return &symbol_yes; 580 case 'm': return &symbol_mod; 581 case 'n': return &symbol_no; 582 } 583 } 584 for (ptr = name; *ptr; ptr++) 585 hash += *ptr; 586 hash &= 0xff; 587 588 for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) { 589 if (!strcmp(symbol->name, name) && 590 !(symbol->flags & SYMBOL_CONST)) 591 break; 592 } 593 594 return symbol; 595} 596 597const char *prop_get_type_name(enum prop_type type) 598{ 599 switch (type) { 600 case P_PROMPT: 601 return "prompt"; 602 case P_COMMENT: 603 return "comment"; 604 case P_MENU: 605 return "menu"; 606 case P_ROOTMENU: 607 return "rootmenu"; 608 case P_DEFAULT: 609 return "default"; 610 case P_CHOICE: 611 return "choice"; 612 default: 613 return "unknown"; 614 } 615} 616