busybox/scripts/kconfig/symbol.c
<<
>>
Prefs
   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 <regex.h>
  10#include <sys/utsname.h>
  11
  12#define LKC_DIRECT_LINK
  13#include "lkc.h"
  14
  15struct symbol symbol_yes = {
  16        .name = "y",
  17        .curr = { "y", yes },
  18        .flags = SYMBOL_YES|SYMBOL_VALID,
  19}, symbol_mod = {
  20        .name = "m",
  21        .curr = { "m", mod },
  22        .flags = SYMBOL_MOD|SYMBOL_VALID,
  23}, symbol_no = {
  24        .name = "n",
  25        .curr = { "n", no },
  26        .flags = SYMBOL_NO|SYMBOL_VALID,
  27}, symbol_empty = {
  28        .name = "",
  29        .curr = { "", no },
  30        .flags = SYMBOL_VALID,
  31};
  32
  33int sym_change_count;
  34struct symbol *modules_sym;
  35tristate modules_val;
  36
  37void sym_add_default(struct symbol *sym, const char *def)
  38{
  39        struct property *prop = prop_alloc(P_DEFAULT, sym);
  40
  41        prop->expr = expr_alloc_symbol(sym_lookup(def, 1));
  42}
  43
  44void sym_init(void)
  45{
  46        struct symbol *sym;
  47        struct utsname uts;
  48        char *p;
  49        static bool inited = false;
  50
  51        if (inited)
  52                return;
  53        inited = true;
  54
  55        uname(&uts);
  56
  57        sym = sym_lookup("ARCH", 0);
  58        sym->type = S_STRING;
  59        sym->flags |= SYMBOL_AUTO;
  60        p = getenv("ARCH");
  61        if (p)
  62                sym_add_default(sym, p);
  63
  64        sym = sym_lookup("KERNELVERSION", 0);
  65        sym->type = S_STRING;
  66        sym->flags |= SYMBOL_AUTO;
  67        p = getenv("KERNELVERSION");
  68        if (p)
  69                sym_add_default(sym, p);
  70
  71        sym = sym_lookup("UNAME_RELEASE", 0);
  72        sym->type = S_STRING;
  73        sym->flags |= SYMBOL_AUTO;
  74        sym_add_default(sym, uts.release);
  75}
  76
  77enum symbol_type sym_get_type(struct symbol *sym)
  78{
  79        enum symbol_type type = sym->type;
  80
  81        if (type == S_TRISTATE) {
  82                if (sym_is_choice_value(sym) && sym->visible == yes)
  83                        type = S_BOOLEAN;
  84                else if (modules_val == no)
  85                        type = S_BOOLEAN;
  86        }
  87        return type;
  88}
  89
  90const char *sym_type_name(enum symbol_type type)
  91{
  92        switch (type) {
  93        case S_BOOLEAN:
  94                return "boolean";
  95        case S_TRISTATE:
  96                return "tristate";
  97        case S_INT:
  98                return "integer";
  99        case S_HEX:
 100                return "hex";
 101        case S_STRING:
 102                return "string";
 103        case S_UNKNOWN:
 104                return "unknown";
 105        case S_OTHER:
 106                break;
 107        }
 108        return "???";
 109}
 110
 111struct property *sym_get_choice_prop(struct symbol *sym)
 112{
 113        struct property *prop;
 114
 115        for_all_choices(sym, prop)
 116                return prop;
 117        return NULL;
 118}
 119
 120struct property *sym_get_default_prop(struct symbol *sym)
 121{
 122        struct property *prop;
 123
 124        for_all_defaults(sym, prop) {
 125                prop->visible.tri = expr_calc_value(prop->visible.expr);
 126                if (prop->visible.tri != no)
 127                        return prop;
 128        }
 129        return NULL;
 130}
 131
 132struct property *sym_get_range_prop(struct symbol *sym)
 133{
 134        struct property *prop;
 135
 136        for_all_properties(sym, prop, P_RANGE) {
 137                prop->visible.tri = expr_calc_value(prop->visible.expr);
 138                if (prop->visible.tri != no)
 139                        return prop;
 140        }
 141        return NULL;
 142}
 143
 144static int sym_get_range_val(struct symbol *sym, int base)
 145{
 146        sym_calc_value(sym);
 147        switch (sym->type) {
 148        case S_INT:
 149                base = 10;
 150                break;
 151        case S_HEX:
 152                base = 16;
 153                break;
 154        default:
 155                break;
 156        }
 157        return strtol(sym->curr.val, NULL, base);
 158}
 159
 160static void sym_validate_range(struct symbol *sym)
 161{
 162        struct property *prop;
 163        int base, val, val2;
 164        char str[64];
 165
 166        switch (sym->type) {
 167        case S_INT:
 168                base = 10;
 169                break;
 170        case S_HEX:
 171                base = 16;
 172                break;
 173        default:
 174                return;
 175        }
 176        prop = sym_get_range_prop(sym);
 177        if (!prop)
 178                return;
 179        val = strtol(sym->curr.val, NULL, base);
 180        val2 = sym_get_range_val(prop->expr->left.sym, base);
 181        if (val >= val2) {
 182                val2 = sym_get_range_val(prop->expr->right.sym, base);
 183                if (val <= val2)
 184                        return;
 185        }
 186        if (sym->type == S_INT)
 187                sprintf(str, "%d", val2);
 188        else
 189                sprintf(str, "0x%x", val2);
 190        sym->curr.val = strdup(str);
 191}
 192
 193static void sym_calc_visibility(struct symbol *sym)
 194{
 195        struct property *prop;
 196        tristate tri;
 197
 198        /* any prompt visible? */
 199        tri = no;
 200        for_all_prompts(sym, prop) {
 201                prop->visible.tri = expr_calc_value(prop->visible.expr);
 202                tri = E_OR(tri, prop->visible.tri);
 203        }
 204        if (tri == mod && (sym->type != S_TRISTATE || modules_val == no))
 205                tri = yes;
 206        if (sym->visible != tri) {
 207                sym->visible = tri;
 208                sym_set_changed(sym);
 209        }
 210        if (sym_is_choice_value(sym))
 211                return;
 212        tri = no;
 213        if (sym->rev_dep.expr)
 214                tri = expr_calc_value(sym->rev_dep.expr);
 215        if (tri == mod && sym_get_type(sym) == S_BOOLEAN)
 216                tri = yes;
 217        if (sym->rev_dep.tri != tri) {
 218                sym->rev_dep.tri = tri;
 219                sym_set_changed(sym);
 220        }
 221}
 222
 223static struct symbol *sym_calc_choice(struct symbol *sym)
 224{
 225        struct symbol *def_sym;
 226        struct property *prop;
 227        struct expr *e;
 228
 229        /* is the user choice visible? */
 230        def_sym = sym->user.val;
 231        if (def_sym) {
 232                sym_calc_visibility(def_sym);
 233                if (def_sym->visible != no)
 234                        return def_sym;
 235        }
 236
 237        /* any of the defaults visible? */
 238        for_all_defaults(sym, prop) {
 239                prop->visible.tri = expr_calc_value(prop->visible.expr);
 240                if (prop->visible.tri == no)
 241                        continue;
 242                def_sym = prop_get_symbol(prop);
 243                sym_calc_visibility(def_sym);
 244                if (def_sym->visible != no)
 245                        return def_sym;
 246        }
 247
 248        /* just get the first visible value */
 249        prop = sym_get_choice_prop(sym);
 250        for (e = prop->expr; e; e = e->left.expr) {
 251                def_sym = e->right.sym;
 252                sym_calc_visibility(def_sym);
 253                if (def_sym->visible != no)
 254                        return def_sym;
 255        }
 256
 257        /* no choice? reset tristate value */
 258        sym->curr.tri = no;
 259        return NULL;
 260}
 261
 262void sym_calc_value(struct symbol *sym)
 263{
 264        struct symbol_value newval, oldval;
 265        struct property *prop;
 266        struct expr *e;
 267
 268        if (!sym)
 269                return;
 270
 271        if (sym->flags & SYMBOL_VALID)
 272                return;
 273        sym->flags |= SYMBOL_VALID;
 274
 275        oldval = sym->curr;
 276
 277        switch (sym->type) {
 278        case S_INT:
 279        case S_HEX:
 280        case S_STRING:
 281                newval = symbol_empty.curr;
 282                break;
 283        case S_BOOLEAN:
 284        case S_TRISTATE:
 285                newval = symbol_no.curr;
 286                break;
 287        default:
 288                sym->curr.val = sym->name;
 289                sym->curr.tri = no;
 290                return;
 291        }
 292        if (!sym_is_choice_value(sym))
 293                sym->flags &= ~SYMBOL_WRITE;
 294
 295        sym_calc_visibility(sym);
 296
 297        /* set default if recursively called */
 298        sym->curr = newval;
 299
 300        switch (sym_get_type(sym)) {
 301        case S_BOOLEAN:
 302        case S_TRISTATE:
 303                if (sym_is_choice_value(sym) && sym->visible == yes) {
 304                        prop = sym_get_choice_prop(sym);
 305                        newval.tri = (prop_get_symbol(prop)->curr.val == sym) ? yes : no;
 306                } else if (E_OR(sym->visible, sym->rev_dep.tri) != no) {
 307                        sym->flags |= SYMBOL_WRITE;
 308                        if (sym_has_value(sym))
 309                                newval.tri = sym->user.tri;
 310                        else if (!sym_is_choice(sym)) {
 311                                prop = sym_get_default_prop(sym);
 312                                if (prop)
 313                                        newval.tri = expr_calc_value(prop->expr);
 314                        }
 315                        newval.tri = E_OR(E_AND(newval.tri, sym->visible), sym->rev_dep.tri);
 316                } else if (!sym_is_choice(sym)) {
 317                        prop = sym_get_default_prop(sym);
 318                        if (prop) {
 319                                sym->flags |= SYMBOL_WRITE;
 320                                newval.tri = expr_calc_value(prop->expr);
 321                        }
 322                }
 323                if (newval.tri == mod && sym_get_type(sym) == S_BOOLEAN)
 324                        newval.tri = yes;
 325                break;
 326        case S_STRING:
 327        case S_HEX:
 328        case S_INT:
 329                if (sym->visible != no) {
 330                        sym->flags |= SYMBOL_WRITE;
 331                        if (sym_has_value(sym)) {
 332                                newval.val = sym->user.val;
 333                                break;
 334                        }
 335                }
 336                prop = sym_get_default_prop(sym);
 337                if (prop) {
 338                        struct symbol *ds = prop_get_symbol(prop);
 339                        if (ds) {
 340                                sym->flags |= SYMBOL_WRITE;
 341                                sym_calc_value(ds);
 342                                newval.val = ds->curr.val;
 343                        }
 344                }
 345                break;
 346        default:
 347                ;
 348        }
 349
 350        sym->curr = newval;
 351        if (sym_is_choice(sym) && newval.tri == yes)
 352                sym->curr.val = sym_calc_choice(sym);
 353        sym_validate_range(sym);
 354
 355        if (memcmp(&oldval, &sym->curr, sizeof(oldval)))
 356                sym_set_changed(sym);
 357        if (modules_sym == sym)
 358                modules_val = modules_sym->curr.tri;
 359
 360        if (sym_is_choice(sym)) {
 361                int flags = sym->flags & (SYMBOL_CHANGED | SYMBOL_WRITE);
 362                prop = sym_get_choice_prop(sym);
 363                for (e = prop->expr; e; e = e->left.expr) {
 364                        e->right.sym->flags |= flags;
 365                        if (flags & SYMBOL_CHANGED)
 366                                sym_set_changed(e->right.sym);
 367                }
 368        }
 369}
 370
 371void sym_clear_all_valid(void)
 372{
 373        struct symbol *sym;
 374        int i;
 375
 376        for_all_symbols(i, sym)
 377                sym->flags &= ~SYMBOL_VALID;
 378        sym_change_count++;
 379        if (modules_sym)
 380                sym_calc_value(modules_sym);
 381}
 382
 383void sym_set_changed(struct symbol *sym)
 384{
 385        struct property *prop;
 386
 387        sym->flags |= SYMBOL_CHANGED;
 388        for (prop = sym->prop; prop; prop = prop->next) {
 389                if (prop->menu)
 390                        prop->menu->flags |= MENU_CHANGED;
 391        }
 392}
 393
 394void sym_set_all_changed(void)
 395{
 396        struct symbol *sym;
 397        int i;
 398
 399        for_all_symbols(i, sym)
 400                sym_set_changed(sym);
 401}
 402
 403bool sym_tristate_within_range(struct symbol *sym, tristate val)
 404{
 405        int type = sym_get_type(sym);
 406
 407        if (sym->visible == no)
 408                return false;
 409
 410        if (type != S_BOOLEAN && type != S_TRISTATE)
 411                return false;
 412
 413        if (type == S_BOOLEAN && val == mod)
 414                return false;
 415        if (sym->visible <= sym->rev_dep.tri)
 416                return false;
 417        if (sym_is_choice_value(sym) && sym->visible == yes)
 418                return val == yes;
 419        return val >= sym->rev_dep.tri && val <= sym->visible;
 420}
 421
 422bool sym_set_tristate_value(struct symbol *sym, tristate val)
 423{
 424        tristate oldval = sym_get_tristate_value(sym);
 425
 426        if (oldval != val && !sym_tristate_within_range(sym, val))
 427                return false;
 428
 429        if (sym->flags & SYMBOL_NEW) {
 430                sym->flags &= ~SYMBOL_NEW;
 431                sym_set_changed(sym);
 432        }
 433        /*
 434         * setting a choice value also resets the new flag of the choice
 435         * symbol and all other choice values.
 436         */
 437        if (sym_is_choice_value(sym) && val == yes) {
 438                struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
 439                struct property *prop;
 440                struct expr *e;
 441
 442                cs->user.val = sym;
 443                cs->flags &= ~SYMBOL_NEW;
 444                prop = sym_get_choice_prop(cs);
 445                for (e = prop->expr; e; e = e->left.expr) {
 446                        if (e->right.sym->visible != no)
 447                                e->right.sym->flags &= ~SYMBOL_NEW;
 448                }
 449        }
 450
 451        sym->user.tri = val;
 452        if (oldval != val) {
 453                sym_clear_all_valid();
 454                if (sym == modules_sym)
 455                        sym_set_all_changed();
 456        }
 457
 458        return true;
 459}
 460
 461tristate sym_toggle_tristate_value(struct symbol *sym)
 462{
 463        tristate oldval, newval;
 464
 465        oldval = newval = sym_get_tristate_value(sym);
 466        do {
 467                switch (newval) {
 468                case no:
 469                        newval = mod;
 470                        break;
 471                case mod:
 472                        newval = yes;
 473                        break;
 474                case yes:
 475                        newval = no;
 476                        break;
 477                }
 478                if (sym_set_tristate_value(sym, newval))
 479                        break;
 480        } while (oldval != newval);
 481        return newval;
 482}
 483
 484bool sym_string_valid(struct symbol *sym, const char *str)
 485{
 486        signed char ch;
 487
 488        switch (sym->type) {
 489        case S_STRING:
 490                return true;
 491        case S_INT:
 492                ch = *str++;
 493                if (ch == '-')
 494                        ch = *str++;
 495                if (!isdigit(ch))
 496                        return false;
 497                if (ch == '0' && *str != 0)
 498                        return false;
 499                while ((ch = *str++)) {
 500                        if (!isdigit(ch))
 501                                return false;
 502                }
 503                return true;
 504        case S_HEX:
 505                if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))
 506                        str += 2;
 507                ch = *str++;
 508                do {
 509                        if (!isxdigit(ch))
 510                                return false;
 511                } while ((ch = *str++));
 512                return true;
 513        case S_BOOLEAN:
 514        case S_TRISTATE:
 515                switch (str[0]) {
 516                case 'y': case 'Y':
 517                case 'm': case 'M':
 518                case 'n': case 'N':
 519                        return true;
 520                }
 521                return false;
 522        default:
 523                return false;
 524        }
 525}
 526
 527bool sym_string_within_range(struct symbol *sym, const char *str)
 528{
 529        struct property *prop;
 530        int val;
 531
 532        switch (sym->type) {
 533        case S_STRING:
 534                return sym_string_valid(sym, str);
 535        case S_INT:
 536                if (!sym_string_valid(sym, str))
 537                        return false;
 538                prop = sym_get_range_prop(sym);
 539                if (!prop)
 540                        return true;
 541                val = strtol(str, NULL, 10);
 542                return val >= sym_get_range_val(prop->expr->left.sym, 10) &&
 543                       val <= sym_get_range_val(prop->expr->right.sym, 10);
 544        case S_HEX:
 545                if (!sym_string_valid(sym, str))
 546                        return false;
 547                prop = sym_get_range_prop(sym);
 548                if (!prop)
 549                        return true;
 550                val = strtol(str, NULL, 16);
 551                return val >= sym_get_range_val(prop->expr->left.sym, 16) &&
 552                       val <= sym_get_range_val(prop->expr->right.sym, 16);
 553        case S_BOOLEAN:
 554        case S_TRISTATE:
 555                switch (str[0]) {
 556                case 'y': case 'Y':
 557                        return sym_tristate_within_range(sym, yes);
 558                case 'm': case 'M':
 559                        return sym_tristate_within_range(sym, mod);
 560                case 'n': case 'N':
 561                        return sym_tristate_within_range(sym, no);
 562                }
 563                return false;
 564        default:
 565                return false;
 566        }
 567}
 568
 569bool sym_set_string_value(struct symbol *sym, const char *newval)
 570{
 571        const char *oldval;
 572        char *val;
 573        int size;
 574
 575        switch (sym->type) {
 576        case S_BOOLEAN:
 577        case S_TRISTATE:
 578                switch (newval[0]) {
 579                case 'y': case 'Y':
 580                        return sym_set_tristate_value(sym, yes);
 581                case 'm': case 'M':
 582                        return sym_set_tristate_value(sym, mod);
 583                case 'n': case 'N':
 584                        return sym_set_tristate_value(sym, no);
 585                }
 586                return false;
 587        default:
 588                ;
 589        }
 590
 591        if (!sym_string_within_range(sym, newval))
 592                return false;
 593
 594        if (sym->flags & SYMBOL_NEW) {
 595                sym->flags &= ~SYMBOL_NEW;
 596                sym_set_changed(sym);
 597        }
 598
 599        oldval = sym->user.val;
 600        size = strlen(newval) + 1;
 601        if (sym->type == S_HEX && (newval[0] != '0' || (newval[1] != 'x' && newval[1] != 'X'))) {
 602                size += 2;
 603                sym->user.val = val = malloc(size);
 604                *val++ = '0';
 605                *val++ = 'x';
 606        } else if (!oldval || strcmp(oldval, newval))
 607                sym->user.val = val = malloc(size);
 608        else
 609                return true;
 610
 611        strcpy(val, newval);
 612        free((void *)oldval);
 613        sym_clear_all_valid();
 614
 615        return true;
 616}
 617
 618const char *sym_get_string_value(struct symbol *sym)
 619{
 620        tristate val;
 621
 622        switch (sym->type) {
 623        case S_BOOLEAN:
 624        case S_TRISTATE:
 625                val = sym_get_tristate_value(sym);
 626                switch (val) {
 627                case no:
 628                        return "n";
 629                case mod:
 630                        return "m";
 631                case yes:
 632                        return "y";
 633                }
 634                break;
 635        default:
 636                ;
 637        }
 638        return (const char *)sym->curr.val;
 639}
 640
 641bool sym_is_changable(struct symbol *sym)
 642{
 643        return sym->visible > sym->rev_dep.tri;
 644}
 645
 646struct symbol *sym_lookup(const char *name, int isconst)
 647{
 648        struct symbol *symbol;
 649        const char *ptr;
 650        char *new_name;
 651        int hash = 0;
 652
 653        if (name) {
 654                if (name[0] && !name[1]) {
 655                        switch (name[0]) {
 656                        case 'y': return &symbol_yes;
 657                        case 'm': return &symbol_mod;
 658                        case 'n': return &symbol_no;
 659                        }
 660                }
 661                for (ptr = name; *ptr; ptr++)
 662                        hash += *ptr;
 663                hash &= 0xff;
 664
 665                for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
 666                        if (!strcmp(symbol->name, name)) {
 667                                if ((isconst && symbol->flags & SYMBOL_CONST) ||
 668                                    (!isconst && !(symbol->flags & SYMBOL_CONST)))
 669                                        return symbol;
 670                        }
 671                }
 672                new_name = strdup(name);
 673        } else {
 674                new_name = NULL;
 675                hash = 256;
 676        }
 677
 678        symbol = malloc(sizeof(*symbol));
 679        memset(symbol, 0, sizeof(*symbol));
 680        symbol->name = new_name;
 681        symbol->type = S_UNKNOWN;
 682        symbol->flags = SYMBOL_NEW;
 683        if (isconst)
 684                symbol->flags |= SYMBOL_CONST;
 685
 686        symbol->next = symbol_hash[hash];
 687        symbol_hash[hash] = symbol;
 688
 689        return symbol;
 690}
 691
 692struct symbol *sym_find(const char *name)
 693{
 694        struct symbol *symbol = NULL;
 695        const char *ptr;
 696        int hash = 0;
 697
 698        if (!name)
 699                return NULL;
 700
 701        if (name[0] && !name[1]) {
 702                switch (name[0]) {
 703                case 'y': return &symbol_yes;
 704                case 'm': return &symbol_mod;
 705                case 'n': return &symbol_no;
 706                }
 707        }
 708        for (ptr = name; *ptr; ptr++)
 709                hash += *ptr;
 710        hash &= 0xff;
 711
 712        for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
 713                if (!strcmp(symbol->name, name) &&
 714                    !(symbol->flags & SYMBOL_CONST))
 715                                break;
 716        }
 717
 718        return symbol;
 719}
 720
 721struct symbol **sym_re_search(const char *pattern)
 722{
 723        struct symbol *sym, **sym_arr = NULL;
 724        int i, cnt, size;
 725        regex_t re;
 726
 727        cnt = size = 0;
 728        /* Skip if empty */
 729        if (strlen(pattern) == 0)
 730                return NULL;
 731        if (regcomp(&re, pattern, REG_EXTENDED|REG_NOSUB|REG_ICASE))
 732                return NULL;
 733
 734        for_all_symbols(i, sym) {
 735                if (sym->flags & SYMBOL_CONST || !sym->name)
 736                        continue;
 737                if (regexec(&re, sym->name, 0, NULL, 0))
 738                        continue;
 739                if (cnt + 1 >= size) {
 740                        void *tmp = sym_arr;
 741                        size += 16;
 742                        sym_arr = realloc(sym_arr, size * sizeof(struct symbol *));
 743                        if (!sym_arr) {
 744                                free(tmp);
 745                                return NULL;
 746                        }
 747                }
 748                sym_arr[cnt++] = sym;
 749        }
 750        if (sym_arr)
 751                sym_arr[cnt] = NULL;
 752        regfree(&re);
 753
 754        return sym_arr;
 755}
 756
 757
 758struct symbol *sym_check_deps(struct symbol *sym);
 759
 760static struct symbol *sym_check_expr_deps(struct expr *e)
 761{
 762        struct symbol *sym;
 763
 764        if (!e)
 765                return NULL;
 766        switch (e->type) {
 767        case E_OR:
 768        case E_AND:
 769                sym = sym_check_expr_deps(e->left.expr);
 770                if (sym)
 771                        return sym;
 772                return sym_check_expr_deps(e->right.expr);
 773        case E_NOT:
 774                return sym_check_expr_deps(e->left.expr);
 775        case E_EQUAL:
 776        case E_UNEQUAL:
 777                sym = sym_check_deps(e->left.sym);
 778                if (sym)
 779                        return sym;
 780                return sym_check_deps(e->right.sym);
 781        case E_SYMBOL:
 782                return sym_check_deps(e->left.sym);
 783        default:
 784                break;
 785        }
 786        printf("Oops! How to check %d?\n", e->type);
 787        return NULL;
 788}
 789
 790struct symbol *sym_check_deps(struct symbol *sym)
 791{
 792        struct symbol *sym2;
 793        struct property *prop;
 794
 795        if (sym->flags & SYMBOL_CHECK) {
 796                printf("Warning! Found recursive dependency: %s", sym->name);
 797                return sym;
 798        }
 799        if (sym->flags & SYMBOL_CHECKED)
 800                return NULL;
 801
 802        sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
 803        sym2 = sym_check_expr_deps(sym->rev_dep.expr);
 804        if (sym2)
 805                goto out;
 806
 807        for (prop = sym->prop; prop; prop = prop->next) {
 808                if (prop->type == P_CHOICE || prop->type == P_SELECT)
 809                        continue;
 810                sym2 = sym_check_expr_deps(prop->visible.expr);
 811                if (sym2)
 812                        goto out;
 813                if (prop->type != P_DEFAULT || sym_is_choice(sym))
 814                        continue;
 815                sym2 = sym_check_expr_deps(prop->expr);
 816                if (sym2)
 817                        goto out;
 818        }
 819out:
 820        if (sym2) {
 821                printf(" %s", sym->name);
 822                if (sym2 == sym) {
 823                        printf("\n");
 824                        sym2 = NULL;
 825                }
 826        }
 827        sym->flags &= ~SYMBOL_CHECK;
 828        return sym2;
 829}
 830
 831struct property *prop_alloc(enum prop_type type, struct symbol *sym)
 832{
 833        struct property *prop;
 834        struct property **propp;
 835
 836        prop = malloc(sizeof(*prop));
 837        memset(prop, 0, sizeof(*prop));
 838        prop->type = type;
 839        prop->sym = sym;
 840        prop->file = current_file;
 841        prop->lineno = zconf_lineno();
 842
 843        /* append property to the prop list of symbol */
 844        if (sym) {
 845                for (propp = &sym->prop; *propp; propp = &(*propp)->next)
 846                        ;
 847                *propp = prop;
 848        }
 849
 850        return prop;
 851}
 852
 853struct symbol *prop_get_symbol(struct property *prop)
 854{
 855        if (prop->expr && (prop->expr->type == E_SYMBOL ||
 856                           prop->expr->type == E_CHOICE))
 857                return prop->expr->left.sym;
 858        return NULL;
 859}
 860
 861const char *prop_get_type_name(enum prop_type type)
 862{
 863        switch (type) {
 864        case P_PROMPT:
 865                return "prompt";
 866        case P_COMMENT:
 867                return "comment";
 868        case P_MENU:
 869                return "menu";
 870        case P_DEFAULT:
 871                return "default";
 872        case P_CHOICE:
 873                return "choice";
 874        case P_SELECT:
 875                return "select";
 876        case P_RANGE:
 877                return "range";
 878        case P_UNKNOWN:
 879                break;
 880        }
 881        return "unknown";
 882}
 883