Root/scripts/config/symbol.c

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}
896

Archive Download this file



interactive