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