source: trunk/scripts/config/symbol.c @ 28658

Last change on this file since 28658 was 28658, checked in by nbd, 5 years ago

scripts/config: merge fixes for various issues, including recursive dependency detection/handling (patch by mbm)

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