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