source: debwrt/trunk/config/mconf/symbol.c @ 1

Last change on this file since 1 was 1, checked in by amain, 13 years ago

Initial import of the build environment for DebWrt

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