Commit 246cf9c26bf11f2bffbecea6e5bd222eee7b1df8
Committed by
Michal Marek
1 parent
60c8eca69f
Exists in
master
and in
7 other branches
kbuild: Warn on selecting symbols with unmet direct dependencies
The "select" statement in Kconfig files allows the enabling of options even if they have unmet direct dependencies (i.e. "depends on" expands to "no"). Currently, the "depends on" clauses are used in calculating the visibility but they do not affect the reverse dependencies in any way. The patch introduces additional tracking of the "depends on" statements and prints a warning on selecting an option if its direct dependencies are not met. Signed-off-by: Catalin Marinas <catalin.marinas@arm.com> Cc: Sam Ravnborg <sam@ravnborg.org> Cc: Arnd Bergmann <arnd@arndb.de> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Michal Marek <mmarek@suse.cz>
Showing 3 changed files with 25 additions and 0 deletions Inline Diff
scripts/kconfig/expr.h
1 | /* | 1 | /* |
2 | * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> | 2 | * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> |
3 | * Released under the terms of the GNU GPL v2.0. | 3 | * Released under the terms of the GNU GPL v2.0. |
4 | */ | 4 | */ |
5 | 5 | ||
6 | #ifndef EXPR_H | 6 | #ifndef EXPR_H |
7 | #define EXPR_H | 7 | #define EXPR_H |
8 | 8 | ||
9 | #ifdef __cplusplus | 9 | #ifdef __cplusplus |
10 | extern "C" { | 10 | extern "C" { |
11 | #endif | 11 | #endif |
12 | 12 | ||
13 | #include <stdio.h> | 13 | #include <stdio.h> |
14 | #ifndef __cplusplus | 14 | #ifndef __cplusplus |
15 | #include <stdbool.h> | 15 | #include <stdbool.h> |
16 | #endif | 16 | #endif |
17 | 17 | ||
18 | struct file { | 18 | struct file { |
19 | struct file *next; | 19 | struct file *next; |
20 | struct file *parent; | 20 | struct file *parent; |
21 | char *name; | 21 | char *name; |
22 | int lineno; | 22 | int lineno; |
23 | int flags; | 23 | int flags; |
24 | }; | 24 | }; |
25 | 25 | ||
26 | #define FILE_BUSY 0x0001 | 26 | #define FILE_BUSY 0x0001 |
27 | #define FILE_SCANNED 0x0002 | 27 | #define FILE_SCANNED 0x0002 |
28 | 28 | ||
29 | typedef enum tristate { | 29 | typedef enum tristate { |
30 | no, mod, yes | 30 | no, mod, yes |
31 | } tristate; | 31 | } tristate; |
32 | 32 | ||
33 | enum expr_type { | 33 | enum expr_type { |
34 | E_NONE, E_OR, E_AND, E_NOT, E_EQUAL, E_UNEQUAL, E_LIST, E_SYMBOL, E_RANGE | 34 | E_NONE, E_OR, E_AND, E_NOT, E_EQUAL, E_UNEQUAL, E_LIST, E_SYMBOL, E_RANGE |
35 | }; | 35 | }; |
36 | 36 | ||
37 | union expr_data { | 37 | union expr_data { |
38 | struct expr *expr; | 38 | struct expr *expr; |
39 | struct symbol *sym; | 39 | struct symbol *sym; |
40 | }; | 40 | }; |
41 | 41 | ||
42 | struct expr { | 42 | struct expr { |
43 | enum expr_type type; | 43 | enum expr_type type; |
44 | union expr_data left, right; | 44 | union expr_data left, right; |
45 | }; | 45 | }; |
46 | 46 | ||
47 | #define EXPR_OR(dep1, dep2) (((dep1)>(dep2))?(dep1):(dep2)) | 47 | #define EXPR_OR(dep1, dep2) (((dep1)>(dep2))?(dep1):(dep2)) |
48 | #define EXPR_AND(dep1, dep2) (((dep1)<(dep2))?(dep1):(dep2)) | 48 | #define EXPR_AND(dep1, dep2) (((dep1)<(dep2))?(dep1):(dep2)) |
49 | #define EXPR_NOT(dep) (2-(dep)) | 49 | #define EXPR_NOT(dep) (2-(dep)) |
50 | 50 | ||
51 | #define expr_list_for_each_sym(l, e, s) \ | 51 | #define expr_list_for_each_sym(l, e, s) \ |
52 | for (e = (l); e && (s = e->right.sym); e = e->left.expr) | 52 | for (e = (l); e && (s = e->right.sym); e = e->left.expr) |
53 | 53 | ||
54 | struct expr_value { | 54 | struct expr_value { |
55 | struct expr *expr; | 55 | struct expr *expr; |
56 | tristate tri; | 56 | tristate tri; |
57 | }; | 57 | }; |
58 | 58 | ||
59 | struct symbol_value { | 59 | struct symbol_value { |
60 | void *val; | 60 | void *val; |
61 | tristate tri; | 61 | tristate tri; |
62 | }; | 62 | }; |
63 | 63 | ||
64 | enum symbol_type { | 64 | enum symbol_type { |
65 | S_UNKNOWN, S_BOOLEAN, S_TRISTATE, S_INT, S_HEX, S_STRING, S_OTHER | 65 | S_UNKNOWN, S_BOOLEAN, S_TRISTATE, S_INT, S_HEX, S_STRING, S_OTHER |
66 | }; | 66 | }; |
67 | 67 | ||
68 | /* enum values are used as index to symbol.def[] */ | 68 | /* enum values are used as index to symbol.def[] */ |
69 | enum { | 69 | enum { |
70 | S_DEF_USER, /* main user value */ | 70 | S_DEF_USER, /* main user value */ |
71 | S_DEF_AUTO, /* values read from auto.conf */ | 71 | S_DEF_AUTO, /* values read from auto.conf */ |
72 | S_DEF_DEF3, /* Reserved for UI usage */ | 72 | S_DEF_DEF3, /* Reserved for UI usage */ |
73 | S_DEF_DEF4, /* Reserved for UI usage */ | 73 | S_DEF_DEF4, /* Reserved for UI usage */ |
74 | S_DEF_COUNT | 74 | S_DEF_COUNT |
75 | }; | 75 | }; |
76 | 76 | ||
77 | struct symbol { | 77 | struct symbol { |
78 | struct symbol *next; | 78 | struct symbol *next; |
79 | char *name; | 79 | char *name; |
80 | enum symbol_type type; | 80 | enum symbol_type type; |
81 | struct symbol_value curr; | 81 | struct symbol_value curr; |
82 | struct symbol_value def[S_DEF_COUNT]; | 82 | struct symbol_value def[S_DEF_COUNT]; |
83 | tristate visible; | 83 | tristate visible; |
84 | int flags; | 84 | int flags; |
85 | struct property *prop; | 85 | struct property *prop; |
86 | struct expr_value dir_dep; | ||
86 | struct expr_value rev_dep; | 87 | struct expr_value rev_dep; |
87 | }; | 88 | }; |
88 | 89 | ||
89 | #define for_all_symbols(i, sym) for (i = 0; i < SYMBOL_HASHSIZE; i++) for (sym = symbol_hash[i]; sym; sym = sym->next) if (sym->type != S_OTHER) | 90 | #define for_all_symbols(i, sym) for (i = 0; i < SYMBOL_HASHSIZE; i++) for (sym = symbol_hash[i]; sym; sym = sym->next) if (sym->type != S_OTHER) |
90 | 91 | ||
91 | #define SYMBOL_CONST 0x0001 /* symbol is const */ | 92 | #define SYMBOL_CONST 0x0001 /* symbol is const */ |
92 | #define SYMBOL_CHECK 0x0008 /* used during dependency checking */ | 93 | #define SYMBOL_CHECK 0x0008 /* used during dependency checking */ |
93 | #define SYMBOL_CHOICE 0x0010 /* start of a choice block (null name) */ | 94 | #define SYMBOL_CHOICE 0x0010 /* start of a choice block (null name) */ |
94 | #define SYMBOL_CHOICEVAL 0x0020 /* used as a value in a choice block */ | 95 | #define SYMBOL_CHOICEVAL 0x0020 /* used as a value in a choice block */ |
95 | #define SYMBOL_VALID 0x0080 /* set when symbol.curr is calculated */ | 96 | #define SYMBOL_VALID 0x0080 /* set when symbol.curr is calculated */ |
96 | #define SYMBOL_OPTIONAL 0x0100 /* choice is optional - values can be 'n' */ | 97 | #define SYMBOL_OPTIONAL 0x0100 /* choice is optional - values can be 'n' */ |
97 | #define SYMBOL_WRITE 0x0200 /* ? */ | 98 | #define SYMBOL_WRITE 0x0200 /* ? */ |
98 | #define SYMBOL_CHANGED 0x0400 /* ? */ | 99 | #define SYMBOL_CHANGED 0x0400 /* ? */ |
99 | #define SYMBOL_AUTO 0x1000 /* value from environment variable */ | 100 | #define SYMBOL_AUTO 0x1000 /* value from environment variable */ |
100 | #define SYMBOL_CHECKED 0x2000 /* used during dependency checking */ | 101 | #define SYMBOL_CHECKED 0x2000 /* used during dependency checking */ |
101 | #define SYMBOL_WARNED 0x8000 /* warning has been issued */ | 102 | #define SYMBOL_WARNED 0x8000 /* warning has been issued */ |
102 | 103 | ||
103 | /* Set when symbol.def[] is used */ | 104 | /* Set when symbol.def[] is used */ |
104 | #define SYMBOL_DEF 0x10000 /* First bit of SYMBOL_DEF */ | 105 | #define SYMBOL_DEF 0x10000 /* First bit of SYMBOL_DEF */ |
105 | #define SYMBOL_DEF_USER 0x10000 /* symbol.def[S_DEF_USER] is valid */ | 106 | #define SYMBOL_DEF_USER 0x10000 /* symbol.def[S_DEF_USER] is valid */ |
106 | #define SYMBOL_DEF_AUTO 0x20000 /* symbol.def[S_DEF_AUTO] is valid */ | 107 | #define SYMBOL_DEF_AUTO 0x20000 /* symbol.def[S_DEF_AUTO] is valid */ |
107 | #define SYMBOL_DEF3 0x40000 /* symbol.def[S_DEF_3] is valid */ | 108 | #define SYMBOL_DEF3 0x40000 /* symbol.def[S_DEF_3] is valid */ |
108 | #define SYMBOL_DEF4 0x80000 /* symbol.def[S_DEF_4] is valid */ | 109 | #define SYMBOL_DEF4 0x80000 /* symbol.def[S_DEF_4] is valid */ |
109 | 110 | ||
110 | #define SYMBOL_MAXLENGTH 256 | 111 | #define SYMBOL_MAXLENGTH 256 |
111 | #define SYMBOL_HASHSIZE 9973 | 112 | #define SYMBOL_HASHSIZE 9973 |
112 | 113 | ||
113 | /* A property represent the config options that can be associated | 114 | /* A property represent the config options that can be associated |
114 | * with a config "symbol". | 115 | * with a config "symbol". |
115 | * Sample: | 116 | * Sample: |
116 | * config FOO | 117 | * config FOO |
117 | * default y | 118 | * default y |
118 | * prompt "foo prompt" | 119 | * prompt "foo prompt" |
119 | * select BAR | 120 | * select BAR |
120 | * config BAZ | 121 | * config BAZ |
121 | * int "BAZ Value" | 122 | * int "BAZ Value" |
122 | * range 1..255 | 123 | * range 1..255 |
123 | */ | 124 | */ |
124 | enum prop_type { | 125 | enum prop_type { |
125 | P_UNKNOWN, | 126 | P_UNKNOWN, |
126 | P_PROMPT, /* prompt "foo prompt" or "BAZ Value" */ | 127 | P_PROMPT, /* prompt "foo prompt" or "BAZ Value" */ |
127 | P_COMMENT, /* text associated with a comment */ | 128 | P_COMMENT, /* text associated with a comment */ |
128 | P_MENU, /* prompt associated with a menuconfig option */ | 129 | P_MENU, /* prompt associated with a menuconfig option */ |
129 | P_DEFAULT, /* default y */ | 130 | P_DEFAULT, /* default y */ |
130 | P_CHOICE, /* choice value */ | 131 | P_CHOICE, /* choice value */ |
131 | P_SELECT, /* select BAR */ | 132 | P_SELECT, /* select BAR */ |
132 | P_RANGE, /* range 7..100 (for a symbol) */ | 133 | P_RANGE, /* range 7..100 (for a symbol) */ |
133 | P_ENV, /* value from environment variable */ | 134 | P_ENV, /* value from environment variable */ |
134 | }; | 135 | }; |
135 | 136 | ||
136 | struct property { | 137 | struct property { |
137 | struct property *next; /* next property - null if last */ | 138 | struct property *next; /* next property - null if last */ |
138 | struct symbol *sym; /* the symbol for which the property is associated */ | 139 | struct symbol *sym; /* the symbol for which the property is associated */ |
139 | enum prop_type type; /* type of property */ | 140 | enum prop_type type; /* type of property */ |
140 | const char *text; /* the prompt value - P_PROMPT, P_MENU, P_COMMENT */ | 141 | const char *text; /* the prompt value - P_PROMPT, P_MENU, P_COMMENT */ |
141 | struct expr_value visible; | 142 | struct expr_value visible; |
142 | struct expr *expr; /* the optional conditional part of the property */ | 143 | struct expr *expr; /* the optional conditional part of the property */ |
143 | struct menu *menu; /* the menu the property are associated with | 144 | struct menu *menu; /* the menu the property are associated with |
144 | * valid for: P_SELECT, P_RANGE, P_CHOICE, | 145 | * valid for: P_SELECT, P_RANGE, P_CHOICE, |
145 | * P_PROMPT, P_DEFAULT, P_MENU, P_COMMENT */ | 146 | * P_PROMPT, P_DEFAULT, P_MENU, P_COMMENT */ |
146 | struct file *file; /* what file was this property defined */ | 147 | struct file *file; /* what file was this property defined */ |
147 | int lineno; /* what lineno was this property defined */ | 148 | int lineno; /* what lineno was this property defined */ |
148 | }; | 149 | }; |
149 | 150 | ||
150 | #define for_all_properties(sym, st, tok) \ | 151 | #define for_all_properties(sym, st, tok) \ |
151 | for (st = sym->prop; st; st = st->next) \ | 152 | for (st = sym->prop; st; st = st->next) \ |
152 | if (st->type == (tok)) | 153 | if (st->type == (tok)) |
153 | #define for_all_defaults(sym, st) for_all_properties(sym, st, P_DEFAULT) | 154 | #define for_all_defaults(sym, st) for_all_properties(sym, st, P_DEFAULT) |
154 | #define for_all_choices(sym, st) for_all_properties(sym, st, P_CHOICE) | 155 | #define for_all_choices(sym, st) for_all_properties(sym, st, P_CHOICE) |
155 | #define for_all_prompts(sym, st) \ | 156 | #define for_all_prompts(sym, st) \ |
156 | for (st = sym->prop; st; st = st->next) \ | 157 | for (st = sym->prop; st; st = st->next) \ |
157 | if (st->text) | 158 | if (st->text) |
158 | 159 | ||
159 | struct menu { | 160 | struct menu { |
160 | struct menu *next; | 161 | struct menu *next; |
161 | struct menu *parent; | 162 | struct menu *parent; |
162 | struct menu *list; | 163 | struct menu *list; |
163 | struct symbol *sym; | 164 | struct symbol *sym; |
164 | struct property *prompt; | 165 | struct property *prompt; |
165 | struct expr *dep; | 166 | struct expr *dep; |
167 | struct expr *dir_dep; | ||
166 | unsigned int flags; | 168 | unsigned int flags; |
167 | char *help; | 169 | char *help; |
168 | struct file *file; | 170 | struct file *file; |
169 | int lineno; | 171 | int lineno; |
170 | void *data; | 172 | void *data; |
171 | }; | 173 | }; |
172 | 174 | ||
173 | #define MENU_CHANGED 0x0001 | 175 | #define MENU_CHANGED 0x0001 |
174 | #define MENU_ROOT 0x0002 | 176 | #define MENU_ROOT 0x0002 |
175 | 177 | ||
176 | #ifndef SWIG | 178 | #ifndef SWIG |
177 | 179 | ||
178 | extern struct file *file_list; | 180 | extern struct file *file_list; |
179 | extern struct file *current_file; | 181 | extern struct file *current_file; |
180 | struct file *lookup_file(const char *name); | 182 | struct file *lookup_file(const char *name); |
181 | 183 | ||
182 | extern struct symbol symbol_yes, symbol_no, symbol_mod; | 184 | extern struct symbol symbol_yes, symbol_no, symbol_mod; |
183 | extern struct symbol *modules_sym; | 185 | extern struct symbol *modules_sym; |
184 | extern struct symbol *sym_defconfig_list; | 186 | extern struct symbol *sym_defconfig_list; |
185 | extern int cdebug; | 187 | extern int cdebug; |
186 | struct expr *expr_alloc_symbol(struct symbol *sym); | 188 | struct expr *expr_alloc_symbol(struct symbol *sym); |
187 | struct expr *expr_alloc_one(enum expr_type type, struct expr *ce); | 189 | struct expr *expr_alloc_one(enum expr_type type, struct expr *ce); |
188 | struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2); | 190 | struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2); |
189 | struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2); | 191 | struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2); |
190 | struct expr *expr_alloc_and(struct expr *e1, struct expr *e2); | 192 | struct expr *expr_alloc_and(struct expr *e1, struct expr *e2); |
191 | struct expr *expr_alloc_or(struct expr *e1, struct expr *e2); | 193 | struct expr *expr_alloc_or(struct expr *e1, struct expr *e2); |
192 | struct expr *expr_copy(struct expr *org); | 194 | struct expr *expr_copy(struct expr *org); |
193 | void expr_free(struct expr *e); | 195 | void expr_free(struct expr *e); |
194 | int expr_eq(struct expr *e1, struct expr *e2); | 196 | int expr_eq(struct expr *e1, struct expr *e2); |
195 | void expr_eliminate_eq(struct expr **ep1, struct expr **ep2); | 197 | void expr_eliminate_eq(struct expr **ep1, struct expr **ep2); |
196 | tristate expr_calc_value(struct expr *e); | 198 | tristate expr_calc_value(struct expr *e); |
197 | struct expr *expr_eliminate_yn(struct expr *e); | 199 | struct expr *expr_eliminate_yn(struct expr *e); |
198 | struct expr *expr_trans_bool(struct expr *e); | 200 | struct expr *expr_trans_bool(struct expr *e); |
199 | struct expr *expr_eliminate_dups(struct expr *e); | 201 | struct expr *expr_eliminate_dups(struct expr *e); |
200 | struct expr *expr_transform(struct expr *e); | 202 | struct expr *expr_transform(struct expr *e); |
201 | int expr_contains_symbol(struct expr *dep, struct symbol *sym); | 203 | int expr_contains_symbol(struct expr *dep, struct symbol *sym); |
202 | bool expr_depends_symbol(struct expr *dep, struct symbol *sym); | 204 | bool expr_depends_symbol(struct expr *dep, struct symbol *sym); |
203 | struct expr *expr_extract_eq_and(struct expr **ep1, struct expr **ep2); | 205 | struct expr *expr_extract_eq_and(struct expr **ep1, struct expr **ep2); |
204 | struct expr *expr_extract_eq_or(struct expr **ep1, struct expr **ep2); | 206 | struct expr *expr_extract_eq_or(struct expr **ep1, struct expr **ep2); |
205 | void expr_extract_eq(enum expr_type type, struct expr **ep, struct expr **ep1, struct expr **ep2); | 207 | void expr_extract_eq(enum expr_type type, struct expr **ep, struct expr **ep1, struct expr **ep2); |
206 | struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym); | 208 | struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym); |
207 | 209 | ||
208 | void expr_fprint(struct expr *e, FILE *out); | 210 | void expr_fprint(struct expr *e, FILE *out); |
209 | struct gstr; /* forward */ | 211 | struct gstr; /* forward */ |
210 | void expr_gstr_print(struct expr *e, struct gstr *gs); | 212 | void expr_gstr_print(struct expr *e, struct gstr *gs); |
211 | 213 | ||
212 | static inline int expr_is_yes(struct expr *e) | 214 | static inline int expr_is_yes(struct expr *e) |
213 | { | 215 | { |
214 | return !e || (e->type == E_SYMBOL && e->left.sym == &symbol_yes); | 216 | return !e || (e->type == E_SYMBOL && e->left.sym == &symbol_yes); |
215 | } | 217 | } |
216 | 218 | ||
217 | static inline int expr_is_no(struct expr *e) | 219 | static inline int expr_is_no(struct expr *e) |
218 | { | 220 | { |
219 | return e && (e->type == E_SYMBOL && e->left.sym == &symbol_no); | 221 | return e && (e->type == E_SYMBOL && e->left.sym == &symbol_no); |
220 | } | 222 | } |
221 | #endif | 223 | #endif |
222 | 224 | ||
223 | #ifdef __cplusplus | 225 | #ifdef __cplusplus |
224 | } | 226 | } |
225 | #endif | 227 | #endif |
226 | 228 | ||
227 | #endif /* EXPR_H */ | 229 | #endif /* EXPR_H */ |
228 | 230 |
scripts/kconfig/menu.c
1 | /* | 1 | /* |
2 | * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> | 2 | * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> |
3 | * Released under the terms of the GNU GPL v2.0. | 3 | * Released under the terms of the GNU GPL v2.0. |
4 | */ | 4 | */ |
5 | 5 | ||
6 | #include <stdlib.h> | 6 | #include <stdlib.h> |
7 | #include <string.h> | 7 | #include <string.h> |
8 | 8 | ||
9 | #define LKC_DIRECT_LINK | 9 | #define LKC_DIRECT_LINK |
10 | #include "lkc.h" | 10 | #include "lkc.h" |
11 | 11 | ||
12 | static const char nohelp_text[] = N_( | 12 | static const char nohelp_text[] = N_( |
13 | "There is no help available for this kernel option.\n"); | 13 | "There is no help available for this kernel option.\n"); |
14 | 14 | ||
15 | struct menu rootmenu; | 15 | struct menu rootmenu; |
16 | static struct menu **last_entry_ptr; | 16 | static struct menu **last_entry_ptr; |
17 | 17 | ||
18 | struct file *file_list; | 18 | struct file *file_list; |
19 | struct file *current_file; | 19 | struct file *current_file; |
20 | 20 | ||
21 | void menu_warn(struct menu *menu, const char *fmt, ...) | 21 | void menu_warn(struct menu *menu, const char *fmt, ...) |
22 | { | 22 | { |
23 | va_list ap; | 23 | va_list ap; |
24 | va_start(ap, fmt); | 24 | va_start(ap, fmt); |
25 | fprintf(stderr, "%s:%d:warning: ", menu->file->name, menu->lineno); | 25 | fprintf(stderr, "%s:%d:warning: ", menu->file->name, menu->lineno); |
26 | vfprintf(stderr, fmt, ap); | 26 | vfprintf(stderr, fmt, ap); |
27 | fprintf(stderr, "\n"); | 27 | fprintf(stderr, "\n"); |
28 | va_end(ap); | 28 | va_end(ap); |
29 | } | 29 | } |
30 | 30 | ||
31 | static void prop_warn(struct property *prop, const char *fmt, ...) | 31 | static void prop_warn(struct property *prop, const char *fmt, ...) |
32 | { | 32 | { |
33 | va_list ap; | 33 | va_list ap; |
34 | va_start(ap, fmt); | 34 | va_start(ap, fmt); |
35 | fprintf(stderr, "%s:%d:warning: ", prop->file->name, prop->lineno); | 35 | fprintf(stderr, "%s:%d:warning: ", prop->file->name, prop->lineno); |
36 | vfprintf(stderr, fmt, ap); | 36 | vfprintf(stderr, fmt, ap); |
37 | fprintf(stderr, "\n"); | 37 | fprintf(stderr, "\n"); |
38 | va_end(ap); | 38 | va_end(ap); |
39 | } | 39 | } |
40 | 40 | ||
41 | void _menu_init(void) | 41 | void _menu_init(void) |
42 | { | 42 | { |
43 | current_entry = current_menu = &rootmenu; | 43 | current_entry = current_menu = &rootmenu; |
44 | last_entry_ptr = &rootmenu.list; | 44 | last_entry_ptr = &rootmenu.list; |
45 | } | 45 | } |
46 | 46 | ||
47 | void menu_add_entry(struct symbol *sym) | 47 | void menu_add_entry(struct symbol *sym) |
48 | { | 48 | { |
49 | struct menu *menu; | 49 | struct menu *menu; |
50 | 50 | ||
51 | menu = malloc(sizeof(*menu)); | 51 | menu = malloc(sizeof(*menu)); |
52 | memset(menu, 0, sizeof(*menu)); | 52 | memset(menu, 0, sizeof(*menu)); |
53 | menu->sym = sym; | 53 | menu->sym = sym; |
54 | menu->parent = current_menu; | 54 | menu->parent = current_menu; |
55 | menu->file = current_file; | 55 | menu->file = current_file; |
56 | menu->lineno = zconf_lineno(); | 56 | menu->lineno = zconf_lineno(); |
57 | 57 | ||
58 | *last_entry_ptr = menu; | 58 | *last_entry_ptr = menu; |
59 | last_entry_ptr = &menu->next; | 59 | last_entry_ptr = &menu->next; |
60 | current_entry = menu; | 60 | current_entry = menu; |
61 | } | 61 | } |
62 | 62 | ||
63 | void menu_end_entry(void) | 63 | void menu_end_entry(void) |
64 | { | 64 | { |
65 | } | 65 | } |
66 | 66 | ||
67 | struct menu *menu_add_menu(void) | 67 | struct menu *menu_add_menu(void) |
68 | { | 68 | { |
69 | menu_end_entry(); | 69 | menu_end_entry(); |
70 | last_entry_ptr = ¤t_entry->list; | 70 | last_entry_ptr = ¤t_entry->list; |
71 | return current_menu = current_entry; | 71 | return current_menu = current_entry; |
72 | } | 72 | } |
73 | 73 | ||
74 | void menu_end_menu(void) | 74 | void menu_end_menu(void) |
75 | { | 75 | { |
76 | last_entry_ptr = ¤t_menu->next; | 76 | last_entry_ptr = ¤t_menu->next; |
77 | current_menu = current_menu->parent; | 77 | current_menu = current_menu->parent; |
78 | } | 78 | } |
79 | 79 | ||
80 | static struct expr *menu_check_dep(struct expr *e) | 80 | static struct expr *menu_check_dep(struct expr *e) |
81 | { | 81 | { |
82 | if (!e) | 82 | if (!e) |
83 | return e; | 83 | return e; |
84 | 84 | ||
85 | switch (e->type) { | 85 | switch (e->type) { |
86 | case E_NOT: | 86 | case E_NOT: |
87 | e->left.expr = menu_check_dep(e->left.expr); | 87 | e->left.expr = menu_check_dep(e->left.expr); |
88 | break; | 88 | break; |
89 | case E_OR: | 89 | case E_OR: |
90 | case E_AND: | 90 | case E_AND: |
91 | e->left.expr = menu_check_dep(e->left.expr); | 91 | e->left.expr = menu_check_dep(e->left.expr); |
92 | e->right.expr = menu_check_dep(e->right.expr); | 92 | e->right.expr = menu_check_dep(e->right.expr); |
93 | break; | 93 | break; |
94 | case E_SYMBOL: | 94 | case E_SYMBOL: |
95 | /* change 'm' into 'm' && MODULES */ | 95 | /* change 'm' into 'm' && MODULES */ |
96 | if (e->left.sym == &symbol_mod) | 96 | if (e->left.sym == &symbol_mod) |
97 | return expr_alloc_and(e, expr_alloc_symbol(modules_sym)); | 97 | return expr_alloc_and(e, expr_alloc_symbol(modules_sym)); |
98 | break; | 98 | break; |
99 | default: | 99 | default: |
100 | break; | 100 | break; |
101 | } | 101 | } |
102 | return e; | 102 | return e; |
103 | } | 103 | } |
104 | 104 | ||
105 | void menu_add_dep(struct expr *dep) | 105 | void menu_add_dep(struct expr *dep) |
106 | { | 106 | { |
107 | current_entry->dep = expr_alloc_and(current_entry->dep, menu_check_dep(dep)); | 107 | current_entry->dep = expr_alloc_and(current_entry->dep, menu_check_dep(dep)); |
108 | current_entry->dir_dep = current_entry->dep; | ||
108 | } | 109 | } |
109 | 110 | ||
110 | void menu_set_type(int type) | 111 | void menu_set_type(int type) |
111 | { | 112 | { |
112 | struct symbol *sym = current_entry->sym; | 113 | struct symbol *sym = current_entry->sym; |
113 | 114 | ||
114 | if (sym->type == type) | 115 | if (sym->type == type) |
115 | return; | 116 | return; |
116 | if (sym->type == S_UNKNOWN) { | 117 | if (sym->type == S_UNKNOWN) { |
117 | sym->type = type; | 118 | sym->type = type; |
118 | return; | 119 | return; |
119 | } | 120 | } |
120 | menu_warn(current_entry, "type of '%s' redefined from '%s' to '%s'", | 121 | menu_warn(current_entry, "type of '%s' redefined from '%s' to '%s'", |
121 | sym->name ? sym->name : "<choice>", | 122 | sym->name ? sym->name : "<choice>", |
122 | sym_type_name(sym->type), sym_type_name(type)); | 123 | sym_type_name(sym->type), sym_type_name(type)); |
123 | } | 124 | } |
124 | 125 | ||
125 | struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep) | 126 | struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep) |
126 | { | 127 | { |
127 | struct property *prop = prop_alloc(type, current_entry->sym); | 128 | struct property *prop = prop_alloc(type, current_entry->sym); |
128 | 129 | ||
129 | prop->menu = current_entry; | 130 | prop->menu = current_entry; |
130 | prop->expr = expr; | 131 | prop->expr = expr; |
131 | prop->visible.expr = menu_check_dep(dep); | 132 | prop->visible.expr = menu_check_dep(dep); |
132 | 133 | ||
133 | if (prompt) { | 134 | if (prompt) { |
134 | if (isspace(*prompt)) { | 135 | if (isspace(*prompt)) { |
135 | prop_warn(prop, "leading whitespace ignored"); | 136 | prop_warn(prop, "leading whitespace ignored"); |
136 | while (isspace(*prompt)) | 137 | while (isspace(*prompt)) |
137 | prompt++; | 138 | prompt++; |
138 | } | 139 | } |
139 | if (current_entry->prompt) | 140 | if (current_entry->prompt) |
140 | prop_warn(prop, "prompt redefined"); | 141 | prop_warn(prop, "prompt redefined"); |
141 | current_entry->prompt = prop; | 142 | current_entry->prompt = prop; |
142 | } | 143 | } |
143 | prop->text = prompt; | 144 | prop->text = prompt; |
144 | 145 | ||
145 | return prop; | 146 | return prop; |
146 | } | 147 | } |
147 | 148 | ||
148 | struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep) | 149 | struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep) |
149 | { | 150 | { |
150 | return menu_add_prop(type, prompt, NULL, dep); | 151 | return menu_add_prop(type, prompt, NULL, dep); |
151 | } | 152 | } |
152 | 153 | ||
153 | void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep) | 154 | void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep) |
154 | { | 155 | { |
155 | menu_add_prop(type, NULL, expr, dep); | 156 | menu_add_prop(type, NULL, expr, dep); |
156 | } | 157 | } |
157 | 158 | ||
158 | void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep) | 159 | void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep) |
159 | { | 160 | { |
160 | menu_add_prop(type, NULL, expr_alloc_symbol(sym), dep); | 161 | menu_add_prop(type, NULL, expr_alloc_symbol(sym), dep); |
161 | } | 162 | } |
162 | 163 | ||
163 | void menu_add_option(int token, char *arg) | 164 | void menu_add_option(int token, char *arg) |
164 | { | 165 | { |
165 | struct property *prop; | 166 | struct property *prop; |
166 | 167 | ||
167 | switch (token) { | 168 | switch (token) { |
168 | case T_OPT_MODULES: | 169 | case T_OPT_MODULES: |
169 | prop = prop_alloc(P_DEFAULT, modules_sym); | 170 | prop = prop_alloc(P_DEFAULT, modules_sym); |
170 | prop->expr = expr_alloc_symbol(current_entry->sym); | 171 | prop->expr = expr_alloc_symbol(current_entry->sym); |
171 | break; | 172 | break; |
172 | case T_OPT_DEFCONFIG_LIST: | 173 | case T_OPT_DEFCONFIG_LIST: |
173 | if (!sym_defconfig_list) | 174 | if (!sym_defconfig_list) |
174 | sym_defconfig_list = current_entry->sym; | 175 | sym_defconfig_list = current_entry->sym; |
175 | else if (sym_defconfig_list != current_entry->sym) | 176 | else if (sym_defconfig_list != current_entry->sym) |
176 | zconf_error("trying to redefine defconfig symbol"); | 177 | zconf_error("trying to redefine defconfig symbol"); |
177 | break; | 178 | break; |
178 | case T_OPT_ENV: | 179 | case T_OPT_ENV: |
179 | prop_add_env(arg); | 180 | prop_add_env(arg); |
180 | break; | 181 | break; |
181 | } | 182 | } |
182 | } | 183 | } |
183 | 184 | ||
184 | static int menu_range_valid_sym(struct symbol *sym, struct symbol *sym2) | 185 | static int menu_range_valid_sym(struct symbol *sym, struct symbol *sym2) |
185 | { | 186 | { |
186 | return sym2->type == S_INT || sym2->type == S_HEX || | 187 | return sym2->type == S_INT || sym2->type == S_HEX || |
187 | (sym2->type == S_UNKNOWN && sym_string_valid(sym, sym2->name)); | 188 | (sym2->type == S_UNKNOWN && sym_string_valid(sym, sym2->name)); |
188 | } | 189 | } |
189 | 190 | ||
190 | static void sym_check_prop(struct symbol *sym) | 191 | static void sym_check_prop(struct symbol *sym) |
191 | { | 192 | { |
192 | struct property *prop; | 193 | struct property *prop; |
193 | struct symbol *sym2; | 194 | struct symbol *sym2; |
194 | for (prop = sym->prop; prop; prop = prop->next) { | 195 | for (prop = sym->prop; prop; prop = prop->next) { |
195 | switch (prop->type) { | 196 | switch (prop->type) { |
196 | case P_DEFAULT: | 197 | case P_DEFAULT: |
197 | if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) && | 198 | if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) && |
198 | prop->expr->type != E_SYMBOL) | 199 | prop->expr->type != E_SYMBOL) |
199 | prop_warn(prop, | 200 | prop_warn(prop, |
200 | "default for config symbol '%s'" | 201 | "default for config symbol '%s'" |
201 | " must be a single symbol", sym->name); | 202 | " must be a single symbol", sym->name); |
202 | break; | 203 | break; |
203 | case P_SELECT: | 204 | case P_SELECT: |
204 | sym2 = prop_get_symbol(prop); | 205 | sym2 = prop_get_symbol(prop); |
205 | if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE) | 206 | if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE) |
206 | prop_warn(prop, | 207 | prop_warn(prop, |
207 | "config symbol '%s' uses select, but is " | 208 | "config symbol '%s' uses select, but is " |
208 | "not boolean or tristate", sym->name); | 209 | "not boolean or tristate", sym->name); |
209 | else if (sym2->type != S_UNKNOWN && | 210 | else if (sym2->type != S_UNKNOWN && |
210 | sym2->type != S_BOOLEAN && | 211 | sym2->type != S_BOOLEAN && |
211 | sym2->type != S_TRISTATE) | 212 | sym2->type != S_TRISTATE) |
212 | prop_warn(prop, | 213 | prop_warn(prop, |
213 | "'%s' has wrong type. 'select' only " | 214 | "'%s' has wrong type. 'select' only " |
214 | "accept arguments of boolean and " | 215 | "accept arguments of boolean and " |
215 | "tristate type", sym2->name); | 216 | "tristate type", sym2->name); |
216 | break; | 217 | break; |
217 | case P_RANGE: | 218 | case P_RANGE: |
218 | if (sym->type != S_INT && sym->type != S_HEX) | 219 | if (sym->type != S_INT && sym->type != S_HEX) |
219 | prop_warn(prop, "range is only allowed " | 220 | prop_warn(prop, "range is only allowed " |
220 | "for int or hex symbols"); | 221 | "for int or hex symbols"); |
221 | if (!menu_range_valid_sym(sym, prop->expr->left.sym) || | 222 | if (!menu_range_valid_sym(sym, prop->expr->left.sym) || |
222 | !menu_range_valid_sym(sym, prop->expr->right.sym)) | 223 | !menu_range_valid_sym(sym, prop->expr->right.sym)) |
223 | prop_warn(prop, "range is invalid"); | 224 | prop_warn(prop, "range is invalid"); |
224 | break; | 225 | break; |
225 | default: | 226 | default: |
226 | ; | 227 | ; |
227 | } | 228 | } |
228 | } | 229 | } |
229 | } | 230 | } |
230 | 231 | ||
231 | void menu_finalize(struct menu *parent) | 232 | void menu_finalize(struct menu *parent) |
232 | { | 233 | { |
233 | struct menu *menu, *last_menu; | 234 | struct menu *menu, *last_menu; |
234 | struct symbol *sym; | 235 | struct symbol *sym; |
235 | struct property *prop; | 236 | struct property *prop; |
236 | struct expr *parentdep, *basedep, *dep, *dep2, **ep; | 237 | struct expr *parentdep, *basedep, *dep, *dep2, **ep; |
237 | 238 | ||
238 | sym = parent->sym; | 239 | sym = parent->sym; |
239 | if (parent->list) { | 240 | if (parent->list) { |
240 | if (sym && sym_is_choice(sym)) { | 241 | if (sym && sym_is_choice(sym)) { |
241 | if (sym->type == S_UNKNOWN) { | 242 | if (sym->type == S_UNKNOWN) { |
242 | /* find the first choice value to find out choice type */ | 243 | /* find the first choice value to find out choice type */ |
243 | current_entry = parent; | 244 | current_entry = parent; |
244 | for (menu = parent->list; menu; menu = menu->next) { | 245 | for (menu = parent->list; menu; menu = menu->next) { |
245 | if (menu->sym && menu->sym->type != S_UNKNOWN) { | 246 | if (menu->sym && menu->sym->type != S_UNKNOWN) { |
246 | menu_set_type(menu->sym->type); | 247 | menu_set_type(menu->sym->type); |
247 | break; | 248 | break; |
248 | } | 249 | } |
249 | } | 250 | } |
250 | } | 251 | } |
251 | /* set the type of the remaining choice values */ | 252 | /* set the type of the remaining choice values */ |
252 | for (menu = parent->list; menu; menu = menu->next) { | 253 | for (menu = parent->list; menu; menu = menu->next) { |
253 | current_entry = menu; | 254 | current_entry = menu; |
254 | if (menu->sym && menu->sym->type == S_UNKNOWN) | 255 | if (menu->sym && menu->sym->type == S_UNKNOWN) |
255 | menu_set_type(sym->type); | 256 | menu_set_type(sym->type); |
256 | } | 257 | } |
257 | parentdep = expr_alloc_symbol(sym); | 258 | parentdep = expr_alloc_symbol(sym); |
258 | } else if (parent->prompt) | 259 | } else if (parent->prompt) |
259 | parentdep = parent->prompt->visible.expr; | 260 | parentdep = parent->prompt->visible.expr; |
260 | else | 261 | else |
261 | parentdep = parent->dep; | 262 | parentdep = parent->dep; |
262 | 263 | ||
263 | for (menu = parent->list; menu; menu = menu->next) { | 264 | for (menu = parent->list; menu; menu = menu->next) { |
264 | basedep = expr_transform(menu->dep); | 265 | basedep = expr_transform(menu->dep); |
265 | basedep = expr_alloc_and(expr_copy(parentdep), basedep); | 266 | basedep = expr_alloc_and(expr_copy(parentdep), basedep); |
266 | basedep = expr_eliminate_dups(basedep); | 267 | basedep = expr_eliminate_dups(basedep); |
267 | menu->dep = basedep; | 268 | menu->dep = basedep; |
268 | if (menu->sym) | 269 | if (menu->sym) |
269 | prop = menu->sym->prop; | 270 | prop = menu->sym->prop; |
270 | else | 271 | else |
271 | prop = menu->prompt; | 272 | prop = menu->prompt; |
272 | for (; prop; prop = prop->next) { | 273 | for (; prop; prop = prop->next) { |
273 | if (prop->menu != menu) | 274 | if (prop->menu != menu) |
274 | continue; | 275 | continue; |
275 | dep = expr_transform(prop->visible.expr); | 276 | dep = expr_transform(prop->visible.expr); |
276 | dep = expr_alloc_and(expr_copy(basedep), dep); | 277 | dep = expr_alloc_and(expr_copy(basedep), dep); |
277 | dep = expr_eliminate_dups(dep); | 278 | dep = expr_eliminate_dups(dep); |
278 | if (menu->sym && menu->sym->type != S_TRISTATE) | 279 | if (menu->sym && menu->sym->type != S_TRISTATE) |
279 | dep = expr_trans_bool(dep); | 280 | dep = expr_trans_bool(dep); |
280 | prop->visible.expr = dep; | 281 | prop->visible.expr = dep; |
281 | if (prop->type == P_SELECT) { | 282 | if (prop->type == P_SELECT) { |
282 | struct symbol *es = prop_get_symbol(prop); | 283 | struct symbol *es = prop_get_symbol(prop); |
283 | es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr, | 284 | es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr, |
284 | expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep))); | 285 | expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep))); |
285 | } | 286 | } |
286 | } | 287 | } |
287 | } | 288 | } |
288 | for (menu = parent->list; menu; menu = menu->next) | 289 | for (menu = parent->list; menu; menu = menu->next) |
289 | menu_finalize(menu); | 290 | menu_finalize(menu); |
290 | } else if (sym) { | 291 | } else if (sym) { |
292 | /* ignore inherited dependencies for dir_dep */ | ||
293 | sym->dir_dep.expr = expr_transform(expr_copy(parent->dir_dep)); | ||
294 | sym->dir_dep.expr = expr_eliminate_dups(sym->dir_dep.expr); | ||
295 | |||
291 | basedep = parent->prompt ? parent->prompt->visible.expr : NULL; | 296 | basedep = parent->prompt ? parent->prompt->visible.expr : NULL; |
292 | basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no); | 297 | basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no); |
293 | basedep = expr_eliminate_dups(expr_transform(basedep)); | 298 | basedep = expr_eliminate_dups(expr_transform(basedep)); |
294 | last_menu = NULL; | 299 | last_menu = NULL; |
295 | for (menu = parent->next; menu; menu = menu->next) { | 300 | for (menu = parent->next; menu; menu = menu->next) { |
296 | dep = menu->prompt ? menu->prompt->visible.expr : menu->dep; | 301 | dep = menu->prompt ? menu->prompt->visible.expr : menu->dep; |
297 | if (!expr_contains_symbol(dep, sym)) | 302 | if (!expr_contains_symbol(dep, sym)) |
298 | break; | 303 | break; |
299 | if (expr_depends_symbol(dep, sym)) | 304 | if (expr_depends_symbol(dep, sym)) |
300 | goto next; | 305 | goto next; |
301 | dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no); | 306 | dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no); |
302 | dep = expr_eliminate_dups(expr_transform(dep)); | 307 | dep = expr_eliminate_dups(expr_transform(dep)); |
303 | dep2 = expr_copy(basedep); | 308 | dep2 = expr_copy(basedep); |
304 | expr_eliminate_eq(&dep, &dep2); | 309 | expr_eliminate_eq(&dep, &dep2); |
305 | expr_free(dep); | 310 | expr_free(dep); |
306 | if (!expr_is_yes(dep2)) { | 311 | if (!expr_is_yes(dep2)) { |
307 | expr_free(dep2); | 312 | expr_free(dep2); |
308 | break; | 313 | break; |
309 | } | 314 | } |
310 | expr_free(dep2); | 315 | expr_free(dep2); |
311 | next: | 316 | next: |
312 | menu_finalize(menu); | 317 | menu_finalize(menu); |
313 | menu->parent = parent; | 318 | menu->parent = parent; |
314 | last_menu = menu; | 319 | last_menu = menu; |
315 | } | 320 | } |
316 | if (last_menu) { | 321 | if (last_menu) { |
317 | parent->list = parent->next; | 322 | parent->list = parent->next; |
318 | parent->next = last_menu->next; | 323 | parent->next = last_menu->next; |
319 | last_menu->next = NULL; | 324 | last_menu->next = NULL; |
320 | } | 325 | } |
321 | } | 326 | } |
322 | for (menu = parent->list; menu; menu = menu->next) { | 327 | for (menu = parent->list; menu; menu = menu->next) { |
323 | if (sym && sym_is_choice(sym) && | 328 | if (sym && sym_is_choice(sym) && |
324 | menu->sym && !sym_is_choice_value(menu->sym)) { | 329 | menu->sym && !sym_is_choice_value(menu->sym)) { |
325 | current_entry = menu; | 330 | current_entry = menu; |
326 | menu->sym->flags |= SYMBOL_CHOICEVAL; | 331 | menu->sym->flags |= SYMBOL_CHOICEVAL; |
327 | if (!menu->prompt) | 332 | if (!menu->prompt) |
328 | menu_warn(menu, "choice value must have a prompt"); | 333 | menu_warn(menu, "choice value must have a prompt"); |
329 | for (prop = menu->sym->prop; prop; prop = prop->next) { | 334 | for (prop = menu->sym->prop; prop; prop = prop->next) { |
330 | if (prop->type == P_DEFAULT) | 335 | if (prop->type == P_DEFAULT) |
331 | prop_warn(prop, "defaults for choice " | 336 | prop_warn(prop, "defaults for choice " |
332 | "values not supported"); | 337 | "values not supported"); |
333 | if (prop->menu == menu) | 338 | if (prop->menu == menu) |
334 | continue; | 339 | continue; |
335 | if (prop->type == P_PROMPT && | 340 | if (prop->type == P_PROMPT && |
336 | prop->menu->parent->sym != sym) | 341 | prop->menu->parent->sym != sym) |
337 | prop_warn(prop, "choice value used outside its choice group"); | 342 | prop_warn(prop, "choice value used outside its choice group"); |
338 | } | 343 | } |
339 | /* Non-tristate choice values of tristate choices must | 344 | /* Non-tristate choice values of tristate choices must |
340 | * depend on the choice being set to Y. The choice | 345 | * depend on the choice being set to Y. The choice |
341 | * values' dependencies were propagated to their | 346 | * values' dependencies were propagated to their |
342 | * properties above, so the change here must be re- | 347 | * properties above, so the change here must be re- |
343 | * propagated. | 348 | * propagated. |
344 | */ | 349 | */ |
345 | if (sym->type == S_TRISTATE && menu->sym->type != S_TRISTATE) { | 350 | if (sym->type == S_TRISTATE && menu->sym->type != S_TRISTATE) { |
346 | basedep = expr_alloc_comp(E_EQUAL, sym, &symbol_yes); | 351 | basedep = expr_alloc_comp(E_EQUAL, sym, &symbol_yes); |
347 | menu->dep = expr_alloc_and(basedep, menu->dep); | 352 | menu->dep = expr_alloc_and(basedep, menu->dep); |
348 | for (prop = menu->sym->prop; prop; prop = prop->next) { | 353 | for (prop = menu->sym->prop; prop; prop = prop->next) { |
349 | if (prop->menu != menu) | 354 | if (prop->menu != menu) |
350 | continue; | 355 | continue; |
351 | prop->visible.expr = expr_alloc_and(expr_copy(basedep), | 356 | prop->visible.expr = expr_alloc_and(expr_copy(basedep), |
352 | prop->visible.expr); | 357 | prop->visible.expr); |
353 | } | 358 | } |
354 | } | 359 | } |
355 | menu_add_symbol(P_CHOICE, sym, NULL); | 360 | menu_add_symbol(P_CHOICE, sym, NULL); |
356 | prop = sym_get_choice_prop(sym); | 361 | prop = sym_get_choice_prop(sym); |
357 | for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr) | 362 | for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr) |
358 | ; | 363 | ; |
359 | *ep = expr_alloc_one(E_LIST, NULL); | 364 | *ep = expr_alloc_one(E_LIST, NULL); |
360 | (*ep)->right.sym = menu->sym; | 365 | (*ep)->right.sym = menu->sym; |
361 | } | 366 | } |
362 | if (menu->list && (!menu->prompt || !menu->prompt->text)) { | 367 | if (menu->list && (!menu->prompt || !menu->prompt->text)) { |
363 | for (last_menu = menu->list; ; last_menu = last_menu->next) { | 368 | for (last_menu = menu->list; ; last_menu = last_menu->next) { |
364 | last_menu->parent = parent; | 369 | last_menu->parent = parent; |
365 | if (!last_menu->next) | 370 | if (!last_menu->next) |
366 | break; | 371 | break; |
367 | } | 372 | } |
368 | last_menu->next = menu->next; | 373 | last_menu->next = menu->next; |
369 | menu->next = menu->list; | 374 | menu->next = menu->list; |
370 | menu->list = NULL; | 375 | menu->list = NULL; |
371 | } | 376 | } |
372 | } | 377 | } |
373 | 378 | ||
374 | if (sym && !(sym->flags & SYMBOL_WARNED)) { | 379 | if (sym && !(sym->flags & SYMBOL_WARNED)) { |
375 | if (sym->type == S_UNKNOWN) | 380 | if (sym->type == S_UNKNOWN) |
376 | menu_warn(parent, "config symbol defined without type"); | 381 | menu_warn(parent, "config symbol defined without type"); |
377 | 382 | ||
378 | if (sym_is_choice(sym) && !parent->prompt) | 383 | if (sym_is_choice(sym) && !parent->prompt) |
379 | menu_warn(parent, "choice must have a prompt"); | 384 | menu_warn(parent, "choice must have a prompt"); |
380 | 385 | ||
381 | /* Check properties connected to this symbol */ | 386 | /* Check properties connected to this symbol */ |
382 | sym_check_prop(sym); | 387 | sym_check_prop(sym); |
383 | sym->flags |= SYMBOL_WARNED; | 388 | sym->flags |= SYMBOL_WARNED; |
384 | } | 389 | } |
385 | 390 | ||
386 | if (sym && !sym_is_optional(sym) && parent->prompt) { | 391 | if (sym && !sym_is_optional(sym) && parent->prompt) { |
387 | sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr, | 392 | sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr, |
388 | expr_alloc_and(parent->prompt->visible.expr, | 393 | expr_alloc_and(parent->prompt->visible.expr, |
389 | expr_alloc_symbol(&symbol_mod))); | 394 | expr_alloc_symbol(&symbol_mod))); |
390 | } | 395 | } |
391 | } | 396 | } |
392 | 397 | ||
393 | bool menu_has_prompt(struct menu *menu) | 398 | bool menu_has_prompt(struct menu *menu) |
394 | { | 399 | { |
395 | if (!menu->prompt) | 400 | if (!menu->prompt) |
396 | return false; | 401 | return false; |
397 | return true; | 402 | return true; |
398 | } | 403 | } |
399 | 404 | ||
400 | bool menu_is_visible(struct menu *menu) | 405 | bool menu_is_visible(struct menu *menu) |
401 | { | 406 | { |
402 | struct menu *child; | 407 | struct menu *child; |
403 | struct symbol *sym; | 408 | struct symbol *sym; |
404 | tristate visible; | 409 | tristate visible; |
405 | 410 | ||
406 | if (!menu->prompt) | 411 | if (!menu->prompt) |
407 | return false; | 412 | return false; |
408 | 413 | ||
409 | sym = menu->sym; | 414 | sym = menu->sym; |
410 | if (sym) { | 415 | if (sym) { |
411 | sym_calc_value(sym); | 416 | sym_calc_value(sym); |
412 | visible = menu->prompt->visible.tri; | 417 | visible = menu->prompt->visible.tri; |
413 | } else | 418 | } else |
414 | visible = menu->prompt->visible.tri = expr_calc_value(menu->prompt->visible.expr); | 419 | visible = menu->prompt->visible.tri = expr_calc_value(menu->prompt->visible.expr); |
415 | 420 | ||
416 | if (visible != no) | 421 | if (visible != no) |
417 | return true; | 422 | return true; |
418 | 423 | ||
419 | if (!sym || sym_get_tristate_value(menu->sym) == no) | 424 | if (!sym || sym_get_tristate_value(menu->sym) == no) |
420 | return false; | 425 | return false; |
421 | 426 | ||
422 | for (child = menu->list; child; child = child->next) { | 427 | for (child = menu->list; child; child = child->next) { |
423 | if (menu_is_visible(child)) { | 428 | if (menu_is_visible(child)) { |
424 | if (sym) | 429 | if (sym) |
425 | sym->flags |= SYMBOL_DEF_USER; | 430 | sym->flags |= SYMBOL_DEF_USER; |
426 | return true; | 431 | return true; |
427 | } | 432 | } |
428 | } | 433 | } |
429 | 434 | ||
430 | return false; | 435 | return false; |
431 | } | 436 | } |
432 | 437 | ||
433 | const char *menu_get_prompt(struct menu *menu) | 438 | const char *menu_get_prompt(struct menu *menu) |
434 | { | 439 | { |
435 | if (menu->prompt) | 440 | if (menu->prompt) |
436 | return menu->prompt->text; | 441 | return menu->prompt->text; |
437 | else if (menu->sym) | 442 | else if (menu->sym) |
438 | return menu->sym->name; | 443 | return menu->sym->name; |
439 | return NULL; | 444 | return NULL; |
440 | } | 445 | } |
441 | 446 | ||
442 | struct menu *menu_get_root_menu(struct menu *menu) | 447 | struct menu *menu_get_root_menu(struct menu *menu) |
443 | { | 448 | { |
444 | return &rootmenu; | 449 | return &rootmenu; |
445 | } | 450 | } |
446 | 451 | ||
447 | struct menu *menu_get_parent_menu(struct menu *menu) | 452 | struct menu *menu_get_parent_menu(struct menu *menu) |
448 | { | 453 | { |
449 | enum prop_type type; | 454 | enum prop_type type; |
450 | 455 | ||
451 | for (; menu != &rootmenu; menu = menu->parent) { | 456 | for (; menu != &rootmenu; menu = menu->parent) { |
452 | type = menu->prompt ? menu->prompt->type : 0; | 457 | type = menu->prompt ? menu->prompt->type : 0; |
453 | if (type == P_MENU) | 458 | if (type == P_MENU) |
454 | break; | 459 | break; |
455 | } | 460 | } |
456 | return menu; | 461 | return menu; |
457 | } | 462 | } |
458 | 463 | ||
459 | bool menu_has_help(struct menu *menu) | 464 | bool menu_has_help(struct menu *menu) |
460 | { | 465 | { |
461 | return menu->help != NULL; | 466 | return menu->help != NULL; |
462 | } | 467 | } |
463 | 468 | ||
464 | const char *menu_get_help(struct menu *menu) | 469 | const char *menu_get_help(struct menu *menu) |
465 | { | 470 | { |
466 | if (menu->help) | 471 | if (menu->help) |
467 | return menu->help; | 472 | return menu->help; |
468 | else | 473 | else |
469 | return ""; | 474 | return ""; |
470 | } | 475 | } |
471 | 476 | ||
472 | static void get_prompt_str(struct gstr *r, struct property *prop) | 477 | static void get_prompt_str(struct gstr *r, struct property *prop) |
473 | { | 478 | { |
474 | int i, j; | 479 | int i, j; |
475 | struct menu *submenu[8], *menu; | 480 | struct menu *submenu[8], *menu; |
476 | 481 | ||
477 | str_printf(r, _("Prompt: %s\n"), _(prop->text)); | 482 | str_printf(r, _("Prompt: %s\n"), _(prop->text)); |
478 | str_printf(r, _(" Defined at %s:%d\n"), prop->menu->file->name, | 483 | str_printf(r, _(" Defined at %s:%d\n"), prop->menu->file->name, |
479 | prop->menu->lineno); | 484 | prop->menu->lineno); |
480 | if (!expr_is_yes(prop->visible.expr)) { | 485 | if (!expr_is_yes(prop->visible.expr)) { |
481 | str_append(r, _(" Depends on: ")); | 486 | str_append(r, _(" Depends on: ")); |
482 | expr_gstr_print(prop->visible.expr, r); | 487 | expr_gstr_print(prop->visible.expr, r); |
483 | str_append(r, "\n"); | 488 | str_append(r, "\n"); |
484 | } | 489 | } |
485 | menu = prop->menu->parent; | 490 | menu = prop->menu->parent; |
486 | for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent) | 491 | for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent) |
487 | submenu[i++] = menu; | 492 | submenu[i++] = menu; |
488 | if (i > 0) { | 493 | if (i > 0) { |
489 | str_printf(r, _(" Location:\n")); | 494 | str_printf(r, _(" Location:\n")); |
490 | for (j = 4; --i >= 0; j += 2) { | 495 | for (j = 4; --i >= 0; j += 2) { |
491 | menu = submenu[i]; | 496 | menu = submenu[i]; |
492 | str_printf(r, "%*c-> %s", j, ' ', _(menu_get_prompt(menu))); | 497 | str_printf(r, "%*c-> %s", j, ' ', _(menu_get_prompt(menu))); |
493 | if (menu->sym) { | 498 | if (menu->sym) { |
494 | str_printf(r, " (%s [=%s])", menu->sym->name ? | 499 | str_printf(r, " (%s [=%s])", menu->sym->name ? |
495 | menu->sym->name : _("<choice>"), | 500 | menu->sym->name : _("<choice>"), |
496 | sym_get_string_value(menu->sym)); | 501 | sym_get_string_value(menu->sym)); |
497 | } | 502 | } |
498 | str_append(r, "\n"); | 503 | str_append(r, "\n"); |
499 | } | 504 | } |
500 | } | 505 | } |
501 | } | 506 | } |
502 | 507 | ||
503 | void get_symbol_str(struct gstr *r, struct symbol *sym) | 508 | void get_symbol_str(struct gstr *r, struct symbol *sym) |
504 | { | 509 | { |
505 | bool hit; | 510 | bool hit; |
506 | struct property *prop; | 511 | struct property *prop; |
507 | 512 | ||
508 | if (sym && sym->name) { | 513 | if (sym && sym->name) { |
509 | str_printf(r, "Symbol: %s [=%s]\n", sym->name, | 514 | str_printf(r, "Symbol: %s [=%s]\n", sym->name, |
510 | sym_get_string_value(sym)); | 515 | sym_get_string_value(sym)); |
511 | str_printf(r, "Type : %s\n", sym_type_name(sym->type)); | 516 | str_printf(r, "Type : %s\n", sym_type_name(sym->type)); |
512 | if (sym->type == S_INT || sym->type == S_HEX) { | 517 | if (sym->type == S_INT || sym->type == S_HEX) { |
513 | prop = sym_get_range_prop(sym); | 518 | prop = sym_get_range_prop(sym); |
514 | if (prop) { | 519 | if (prop) { |
515 | str_printf(r, "Range : "); | 520 | str_printf(r, "Range : "); |
516 | expr_gstr_print(prop->expr, r); | 521 | expr_gstr_print(prop->expr, r); |
517 | str_append(r, "\n"); | 522 | str_append(r, "\n"); |
518 | } | 523 | } |
519 | } | 524 | } |
520 | } | 525 | } |
521 | for_all_prompts(sym, prop) | 526 | for_all_prompts(sym, prop) |
522 | get_prompt_str(r, prop); | 527 | get_prompt_str(r, prop); |
523 | hit = false; | 528 | hit = false; |
524 | for_all_properties(sym, prop, P_SELECT) { | 529 | for_all_properties(sym, prop, P_SELECT) { |
525 | if (!hit) { | 530 | if (!hit) { |
526 | str_append(r, " Selects: "); | 531 | str_append(r, " Selects: "); |
527 | hit = true; | 532 | hit = true; |
528 | } else | 533 | } else |
529 | str_printf(r, " && "); | 534 | str_printf(r, " && "); |
530 | expr_gstr_print(prop->expr, r); | 535 | expr_gstr_print(prop->expr, r); |
531 | } | 536 | } |
532 | if (hit) | 537 | if (hit) |
533 | str_append(r, "\n"); | 538 | str_append(r, "\n"); |
534 | if (sym->rev_dep.expr) { | 539 | if (sym->rev_dep.expr) { |
535 | str_append(r, _(" Selected by: ")); | 540 | str_append(r, _(" Selected by: ")); |
536 | expr_gstr_print(sym->rev_dep.expr, r); | 541 | expr_gstr_print(sym->rev_dep.expr, r); |
537 | str_append(r, "\n"); | 542 | str_append(r, "\n"); |
538 | } | 543 | } |
539 | str_append(r, "\n\n"); | 544 | str_append(r, "\n\n"); |
540 | } | 545 | } |
541 | 546 | ||
542 | struct gstr get_relations_str(struct symbol **sym_arr) | 547 | struct gstr get_relations_str(struct symbol **sym_arr) |
543 | { | 548 | { |
544 | struct symbol *sym; | 549 | struct symbol *sym; |
545 | struct gstr res = str_new(); | 550 | struct gstr res = str_new(); |
546 | int i; | 551 | int i; |
547 | 552 | ||
548 | for (i = 0; sym_arr && (sym = sym_arr[i]); i++) | 553 | for (i = 0; sym_arr && (sym = sym_arr[i]); i++) |
549 | get_symbol_str(&res, sym); | 554 | get_symbol_str(&res, sym); |
550 | if (!i) | 555 | if (!i) |
551 | str_append(&res, _("No matches found.\n")); | 556 | str_append(&res, _("No matches found.\n")); |
552 | return res; | 557 | return res; |
553 | } | 558 | } |
554 | 559 | ||
555 | 560 | ||
556 | void menu_get_ext_help(struct menu *menu, struct gstr *help) | 561 | void menu_get_ext_help(struct menu *menu, struct gstr *help) |
557 | { | 562 | { |
558 | struct symbol *sym = menu->sym; | 563 | struct symbol *sym = menu->sym; |
559 | 564 | ||
560 | if (menu_has_help(menu)) { | 565 | if (menu_has_help(menu)) { |
561 | if (sym->name) { | 566 | if (sym->name) { |
562 | str_printf(help, "CONFIG_%s:\n\n", sym->name); | 567 | str_printf(help, "CONFIG_%s:\n\n", sym->name); |
563 | str_append(help, _(menu_get_help(menu))); | 568 | str_append(help, _(menu_get_help(menu))); |
564 | str_append(help, "\n"); | 569 | str_append(help, "\n"); |
565 | } | 570 | } |
566 | } else { | 571 | } else { |
567 | str_append(help, nohelp_text); | 572 | str_append(help, nohelp_text); |
568 | } | 573 | } |
569 | if (sym) | 574 | if (sym) |
570 | get_symbol_str(help, sym); | 575 | get_symbol_str(help, sym); |
571 | } | 576 | } |
572 | 577 |
scripts/kconfig/symbol.c
1 | /* | 1 | /* |
2 | * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> | 2 | * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> |
3 | * Released under the terms of the GNU GPL v2.0. | 3 | * Released under the terms of the GNU GPL v2.0. |
4 | */ | 4 | */ |
5 | 5 | ||
6 | #include <ctype.h> | 6 | #include <ctype.h> |
7 | #include <stdlib.h> | 7 | #include <stdlib.h> |
8 | #include <string.h> | 8 | #include <string.h> |
9 | #include <regex.h> | 9 | #include <regex.h> |
10 | #include <sys/utsname.h> | 10 | #include <sys/utsname.h> |
11 | 11 | ||
12 | #define LKC_DIRECT_LINK | 12 | #define LKC_DIRECT_LINK |
13 | #include "lkc.h" | 13 | #include "lkc.h" |
14 | 14 | ||
15 | struct symbol symbol_yes = { | 15 | struct symbol symbol_yes = { |
16 | .name = "y", | 16 | .name = "y", |
17 | .curr = { "y", yes }, | 17 | .curr = { "y", yes }, |
18 | .flags = SYMBOL_CONST|SYMBOL_VALID, | 18 | .flags = SYMBOL_CONST|SYMBOL_VALID, |
19 | }, symbol_mod = { | 19 | }, symbol_mod = { |
20 | .name = "m", | 20 | .name = "m", |
21 | .curr = { "m", mod }, | 21 | .curr = { "m", mod }, |
22 | .flags = SYMBOL_CONST|SYMBOL_VALID, | 22 | .flags = SYMBOL_CONST|SYMBOL_VALID, |
23 | }, symbol_no = { | 23 | }, symbol_no = { |
24 | .name = "n", | 24 | .name = "n", |
25 | .curr = { "n", no }, | 25 | .curr = { "n", no }, |
26 | .flags = SYMBOL_CONST|SYMBOL_VALID, | 26 | .flags = SYMBOL_CONST|SYMBOL_VALID, |
27 | }, symbol_empty = { | 27 | }, symbol_empty = { |
28 | .name = "", | 28 | .name = "", |
29 | .curr = { "", no }, | 29 | .curr = { "", no }, |
30 | .flags = SYMBOL_VALID, | 30 | .flags = SYMBOL_VALID, |
31 | }; | 31 | }; |
32 | 32 | ||
33 | struct symbol *sym_defconfig_list; | 33 | struct symbol *sym_defconfig_list; |
34 | struct symbol *modules_sym; | 34 | struct symbol *modules_sym; |
35 | tristate modules_val; | 35 | tristate modules_val; |
36 | 36 | ||
37 | struct expr *sym_env_list; | 37 | struct expr *sym_env_list; |
38 | 38 | ||
39 | static void sym_add_default(struct symbol *sym, const char *def) | 39 | static void sym_add_default(struct symbol *sym, const char *def) |
40 | { | 40 | { |
41 | struct property *prop = prop_alloc(P_DEFAULT, sym); | 41 | struct property *prop = prop_alloc(P_DEFAULT, sym); |
42 | 42 | ||
43 | prop->expr = expr_alloc_symbol(sym_lookup(def, SYMBOL_CONST)); | 43 | prop->expr = expr_alloc_symbol(sym_lookup(def, SYMBOL_CONST)); |
44 | } | 44 | } |
45 | 45 | ||
46 | void sym_init(void) | 46 | void sym_init(void) |
47 | { | 47 | { |
48 | struct symbol *sym; | 48 | struct symbol *sym; |
49 | struct utsname uts; | 49 | struct utsname uts; |
50 | static bool inited = false; | 50 | static bool inited = false; |
51 | 51 | ||
52 | if (inited) | 52 | if (inited) |
53 | return; | 53 | return; |
54 | inited = true; | 54 | inited = true; |
55 | 55 | ||
56 | uname(&uts); | 56 | uname(&uts); |
57 | 57 | ||
58 | sym = sym_lookup("UNAME_RELEASE", 0); | 58 | sym = sym_lookup("UNAME_RELEASE", 0); |
59 | sym->type = S_STRING; | 59 | sym->type = S_STRING; |
60 | sym->flags |= SYMBOL_AUTO; | 60 | sym->flags |= SYMBOL_AUTO; |
61 | sym_add_default(sym, uts.release); | 61 | sym_add_default(sym, uts.release); |
62 | } | 62 | } |
63 | 63 | ||
64 | enum symbol_type sym_get_type(struct symbol *sym) | 64 | enum symbol_type sym_get_type(struct symbol *sym) |
65 | { | 65 | { |
66 | enum symbol_type type = sym->type; | 66 | enum symbol_type type = sym->type; |
67 | 67 | ||
68 | if (type == S_TRISTATE) { | 68 | if (type == S_TRISTATE) { |
69 | if (sym_is_choice_value(sym) && sym->visible == yes) | 69 | if (sym_is_choice_value(sym) && sym->visible == yes) |
70 | type = S_BOOLEAN; | 70 | type = S_BOOLEAN; |
71 | else if (modules_val == no) | 71 | else if (modules_val == no) |
72 | type = S_BOOLEAN; | 72 | type = S_BOOLEAN; |
73 | } | 73 | } |
74 | return type; | 74 | return type; |
75 | } | 75 | } |
76 | 76 | ||
77 | const char *sym_type_name(enum symbol_type type) | 77 | const char *sym_type_name(enum symbol_type type) |
78 | { | 78 | { |
79 | switch (type) { | 79 | switch (type) { |
80 | case S_BOOLEAN: | 80 | case S_BOOLEAN: |
81 | return "boolean"; | 81 | return "boolean"; |
82 | case S_TRISTATE: | 82 | case S_TRISTATE: |
83 | return "tristate"; | 83 | return "tristate"; |
84 | case S_INT: | 84 | case S_INT: |
85 | return "integer"; | 85 | return "integer"; |
86 | case S_HEX: | 86 | case S_HEX: |
87 | return "hex"; | 87 | return "hex"; |
88 | case S_STRING: | 88 | case S_STRING: |
89 | return "string"; | 89 | return "string"; |
90 | case S_UNKNOWN: | 90 | case S_UNKNOWN: |
91 | return "unknown"; | 91 | return "unknown"; |
92 | case S_OTHER: | 92 | case S_OTHER: |
93 | break; | 93 | break; |
94 | } | 94 | } |
95 | return "???"; | 95 | return "???"; |
96 | } | 96 | } |
97 | 97 | ||
98 | struct property *sym_get_choice_prop(struct symbol *sym) | 98 | struct property *sym_get_choice_prop(struct symbol *sym) |
99 | { | 99 | { |
100 | struct property *prop; | 100 | struct property *prop; |
101 | 101 | ||
102 | for_all_choices(sym, prop) | 102 | for_all_choices(sym, prop) |
103 | return prop; | 103 | return prop; |
104 | return NULL; | 104 | return NULL; |
105 | } | 105 | } |
106 | 106 | ||
107 | struct property *sym_get_env_prop(struct symbol *sym) | 107 | struct property *sym_get_env_prop(struct symbol *sym) |
108 | { | 108 | { |
109 | struct property *prop; | 109 | struct property *prop; |
110 | 110 | ||
111 | for_all_properties(sym, prop, P_ENV) | 111 | for_all_properties(sym, prop, P_ENV) |
112 | return prop; | 112 | return prop; |
113 | return NULL; | 113 | return NULL; |
114 | } | 114 | } |
115 | 115 | ||
116 | struct property *sym_get_default_prop(struct symbol *sym) | 116 | struct property *sym_get_default_prop(struct symbol *sym) |
117 | { | 117 | { |
118 | struct property *prop; | 118 | struct property *prop; |
119 | 119 | ||
120 | for_all_defaults(sym, prop) { | 120 | for_all_defaults(sym, prop) { |
121 | prop->visible.tri = expr_calc_value(prop->visible.expr); | 121 | prop->visible.tri = expr_calc_value(prop->visible.expr); |
122 | if (prop->visible.tri != no) | 122 | if (prop->visible.tri != no) |
123 | return prop; | 123 | return prop; |
124 | } | 124 | } |
125 | return NULL; | 125 | return NULL; |
126 | } | 126 | } |
127 | 127 | ||
128 | static struct property *sym_get_range_prop(struct symbol *sym) | 128 | static struct property *sym_get_range_prop(struct symbol *sym) |
129 | { | 129 | { |
130 | struct property *prop; | 130 | struct property *prop; |
131 | 131 | ||
132 | for_all_properties(sym, prop, P_RANGE) { | 132 | for_all_properties(sym, prop, P_RANGE) { |
133 | prop->visible.tri = expr_calc_value(prop->visible.expr); | 133 | prop->visible.tri = expr_calc_value(prop->visible.expr); |
134 | if (prop->visible.tri != no) | 134 | if (prop->visible.tri != no) |
135 | return prop; | 135 | return prop; |
136 | } | 136 | } |
137 | return NULL; | 137 | return NULL; |
138 | } | 138 | } |
139 | 139 | ||
140 | static int sym_get_range_val(struct symbol *sym, int base) | 140 | static int sym_get_range_val(struct symbol *sym, int base) |
141 | { | 141 | { |
142 | sym_calc_value(sym); | 142 | sym_calc_value(sym); |
143 | switch (sym->type) { | 143 | switch (sym->type) { |
144 | case S_INT: | 144 | case S_INT: |
145 | base = 10; | 145 | base = 10; |
146 | break; | 146 | break; |
147 | case S_HEX: | 147 | case S_HEX: |
148 | base = 16; | 148 | base = 16; |
149 | break; | 149 | break; |
150 | default: | 150 | default: |
151 | break; | 151 | break; |
152 | } | 152 | } |
153 | return strtol(sym->curr.val, NULL, base); | 153 | return strtol(sym->curr.val, NULL, base); |
154 | } | 154 | } |
155 | 155 | ||
156 | static void sym_validate_range(struct symbol *sym) | 156 | static void sym_validate_range(struct symbol *sym) |
157 | { | 157 | { |
158 | struct property *prop; | 158 | struct property *prop; |
159 | int base, val, val2; | 159 | int base, val, val2; |
160 | char str[64]; | 160 | char str[64]; |
161 | 161 | ||
162 | switch (sym->type) { | 162 | switch (sym->type) { |
163 | case S_INT: | 163 | case S_INT: |
164 | base = 10; | 164 | base = 10; |
165 | break; | 165 | break; |
166 | case S_HEX: | 166 | case S_HEX: |
167 | base = 16; | 167 | base = 16; |
168 | break; | 168 | break; |
169 | default: | 169 | default: |
170 | return; | 170 | return; |
171 | } | 171 | } |
172 | prop = sym_get_range_prop(sym); | 172 | prop = sym_get_range_prop(sym); |
173 | if (!prop) | 173 | if (!prop) |
174 | return; | 174 | return; |
175 | val = strtol(sym->curr.val, NULL, base); | 175 | val = strtol(sym->curr.val, NULL, base); |
176 | val2 = sym_get_range_val(prop->expr->left.sym, base); | 176 | val2 = sym_get_range_val(prop->expr->left.sym, base); |
177 | if (val >= val2) { | 177 | if (val >= val2) { |
178 | val2 = sym_get_range_val(prop->expr->right.sym, base); | 178 | val2 = sym_get_range_val(prop->expr->right.sym, base); |
179 | if (val <= val2) | 179 | if (val <= val2) |
180 | return; | 180 | return; |
181 | } | 181 | } |
182 | if (sym->type == S_INT) | 182 | if (sym->type == S_INT) |
183 | sprintf(str, "%d", val2); | 183 | sprintf(str, "%d", val2); |
184 | else | 184 | else |
185 | sprintf(str, "0x%x", val2); | 185 | sprintf(str, "0x%x", val2); |
186 | sym->curr.val = strdup(str); | 186 | sym->curr.val = strdup(str); |
187 | } | 187 | } |
188 | 188 | ||
189 | static void sym_calc_visibility(struct symbol *sym) | 189 | static void sym_calc_visibility(struct symbol *sym) |
190 | { | 190 | { |
191 | struct property *prop; | 191 | struct property *prop; |
192 | tristate tri; | 192 | tristate tri; |
193 | 193 | ||
194 | /* any prompt visible? */ | 194 | /* any prompt visible? */ |
195 | tri = no; | 195 | tri = no; |
196 | for_all_prompts(sym, prop) { | 196 | for_all_prompts(sym, prop) { |
197 | prop->visible.tri = expr_calc_value(prop->visible.expr); | 197 | prop->visible.tri = expr_calc_value(prop->visible.expr); |
198 | tri = EXPR_OR(tri, prop->visible.tri); | 198 | tri = EXPR_OR(tri, prop->visible.tri); |
199 | } | 199 | } |
200 | if (tri == mod && (sym->type != S_TRISTATE || modules_val == no)) | 200 | if (tri == mod && (sym->type != S_TRISTATE || modules_val == no)) |
201 | tri = yes; | 201 | tri = yes; |
202 | if (sym->visible != tri) { | 202 | if (sym->visible != tri) { |
203 | sym->visible = tri; | 203 | sym->visible = tri; |
204 | sym_set_changed(sym); | 204 | sym_set_changed(sym); |
205 | } | 205 | } |
206 | if (sym_is_choice_value(sym)) | 206 | if (sym_is_choice_value(sym)) |
207 | return; | 207 | return; |
208 | /* defaulting to "yes" if no explicit "depends on" are given */ | ||
209 | tri = yes; | ||
210 | if (sym->dir_dep.expr) | ||
211 | tri = expr_calc_value(sym->dir_dep.expr); | ||
212 | if (tri == mod) | ||
213 | tri = yes; | ||
214 | if (sym->dir_dep.tri != tri) { | ||
215 | sym->dir_dep.tri = tri; | ||
216 | sym_set_changed(sym); | ||
217 | } | ||
208 | tri = no; | 218 | tri = no; |
209 | if (sym->rev_dep.expr) | 219 | if (sym->rev_dep.expr) |
210 | tri = expr_calc_value(sym->rev_dep.expr); | 220 | tri = expr_calc_value(sym->rev_dep.expr); |
211 | if (tri == mod && sym_get_type(sym) == S_BOOLEAN) | 221 | if (tri == mod && sym_get_type(sym) == S_BOOLEAN) |
212 | tri = yes; | 222 | tri = yes; |
213 | if (sym->rev_dep.tri != tri) { | 223 | if (sym->rev_dep.tri != tri) { |
214 | sym->rev_dep.tri = tri; | 224 | sym->rev_dep.tri = tri; |
215 | sym_set_changed(sym); | 225 | sym_set_changed(sym); |
216 | } | 226 | } |
217 | } | 227 | } |
218 | 228 | ||
219 | static struct symbol *sym_calc_choice(struct symbol *sym) | 229 | static struct symbol *sym_calc_choice(struct symbol *sym) |
220 | { | 230 | { |
221 | struct symbol *def_sym; | 231 | struct symbol *def_sym; |
222 | struct property *prop; | 232 | struct property *prop; |
223 | struct expr *e; | 233 | struct expr *e; |
224 | 234 | ||
225 | /* is the user choice visible? */ | 235 | /* is the user choice visible? */ |
226 | def_sym = sym->def[S_DEF_USER].val; | 236 | def_sym = sym->def[S_DEF_USER].val; |
227 | if (def_sym) { | 237 | if (def_sym) { |
228 | sym_calc_visibility(def_sym); | 238 | sym_calc_visibility(def_sym); |
229 | if (def_sym->visible != no) | 239 | if (def_sym->visible != no) |
230 | return def_sym; | 240 | return def_sym; |
231 | } | 241 | } |
232 | 242 | ||
233 | /* any of the defaults visible? */ | 243 | /* any of the defaults visible? */ |
234 | for_all_defaults(sym, prop) { | 244 | for_all_defaults(sym, prop) { |
235 | prop->visible.tri = expr_calc_value(prop->visible.expr); | 245 | prop->visible.tri = expr_calc_value(prop->visible.expr); |
236 | if (prop->visible.tri == no) | 246 | if (prop->visible.tri == no) |
237 | continue; | 247 | continue; |
238 | def_sym = prop_get_symbol(prop); | 248 | def_sym = prop_get_symbol(prop); |
239 | sym_calc_visibility(def_sym); | 249 | sym_calc_visibility(def_sym); |
240 | if (def_sym->visible != no) | 250 | if (def_sym->visible != no) |
241 | return def_sym; | 251 | return def_sym; |
242 | } | 252 | } |
243 | 253 | ||
244 | /* just get the first visible value */ | 254 | /* just get the first visible value */ |
245 | prop = sym_get_choice_prop(sym); | 255 | prop = sym_get_choice_prop(sym); |
246 | expr_list_for_each_sym(prop->expr, e, def_sym) { | 256 | expr_list_for_each_sym(prop->expr, e, def_sym) { |
247 | sym_calc_visibility(def_sym); | 257 | sym_calc_visibility(def_sym); |
248 | if (def_sym->visible != no) | 258 | if (def_sym->visible != no) |
249 | return def_sym; | 259 | return def_sym; |
250 | } | 260 | } |
251 | 261 | ||
252 | /* no choice? reset tristate value */ | 262 | /* no choice? reset tristate value */ |
253 | sym->curr.tri = no; | 263 | sym->curr.tri = no; |
254 | return NULL; | 264 | return NULL; |
255 | } | 265 | } |
256 | 266 | ||
257 | void sym_calc_value(struct symbol *sym) | 267 | void sym_calc_value(struct symbol *sym) |
258 | { | 268 | { |
259 | struct symbol_value newval, oldval; | 269 | struct symbol_value newval, oldval; |
260 | struct property *prop; | 270 | struct property *prop; |
261 | struct expr *e; | 271 | struct expr *e; |
262 | 272 | ||
263 | if (!sym) | 273 | if (!sym) |
264 | return; | 274 | return; |
265 | 275 | ||
266 | if (sym->flags & SYMBOL_VALID) | 276 | if (sym->flags & SYMBOL_VALID) |
267 | return; | 277 | return; |
268 | sym->flags |= SYMBOL_VALID; | 278 | sym->flags |= SYMBOL_VALID; |
269 | 279 | ||
270 | oldval = sym->curr; | 280 | oldval = sym->curr; |
271 | 281 | ||
272 | switch (sym->type) { | 282 | switch (sym->type) { |
273 | case S_INT: | 283 | case S_INT: |
274 | case S_HEX: | 284 | case S_HEX: |
275 | case S_STRING: | 285 | case S_STRING: |
276 | newval = symbol_empty.curr; | 286 | newval = symbol_empty.curr; |
277 | break; | 287 | break; |
278 | case S_BOOLEAN: | 288 | case S_BOOLEAN: |
279 | case S_TRISTATE: | 289 | case S_TRISTATE: |
280 | newval = symbol_no.curr; | 290 | newval = symbol_no.curr; |
281 | break; | 291 | break; |
282 | default: | 292 | default: |
283 | sym->curr.val = sym->name; | 293 | sym->curr.val = sym->name; |
284 | sym->curr.tri = no; | 294 | sym->curr.tri = no; |
285 | return; | 295 | return; |
286 | } | 296 | } |
287 | if (!sym_is_choice_value(sym)) | 297 | if (!sym_is_choice_value(sym)) |
288 | sym->flags &= ~SYMBOL_WRITE; | 298 | sym->flags &= ~SYMBOL_WRITE; |
289 | 299 | ||
290 | sym_calc_visibility(sym); | 300 | sym_calc_visibility(sym); |
291 | 301 | ||
292 | /* set default if recursively called */ | 302 | /* set default if recursively called */ |
293 | sym->curr = newval; | 303 | sym->curr = newval; |
294 | 304 | ||
295 | switch (sym_get_type(sym)) { | 305 | switch (sym_get_type(sym)) { |
296 | case S_BOOLEAN: | 306 | case S_BOOLEAN: |
297 | case S_TRISTATE: | 307 | case S_TRISTATE: |
298 | if (sym_is_choice_value(sym) && sym->visible == yes) { | 308 | if (sym_is_choice_value(sym) && sym->visible == yes) { |
299 | prop = sym_get_choice_prop(sym); | 309 | prop = sym_get_choice_prop(sym); |
300 | newval.tri = (prop_get_symbol(prop)->curr.val == sym) ? yes : no; | 310 | newval.tri = (prop_get_symbol(prop)->curr.val == sym) ? yes : no; |
301 | } else { | 311 | } else { |
302 | if (sym->visible != no) { | 312 | if (sym->visible != no) { |
303 | /* if the symbol is visible use the user value | 313 | /* if the symbol is visible use the user value |
304 | * if available, otherwise try the default value | 314 | * if available, otherwise try the default value |
305 | */ | 315 | */ |
306 | sym->flags |= SYMBOL_WRITE; | 316 | sym->flags |= SYMBOL_WRITE; |
307 | if (sym_has_value(sym)) { | 317 | if (sym_has_value(sym)) { |
308 | newval.tri = EXPR_AND(sym->def[S_DEF_USER].tri, | 318 | newval.tri = EXPR_AND(sym->def[S_DEF_USER].tri, |
309 | sym->visible); | 319 | sym->visible); |
310 | goto calc_newval; | 320 | goto calc_newval; |
311 | } | 321 | } |
312 | } | 322 | } |
313 | if (sym->rev_dep.tri != no) | 323 | if (sym->rev_dep.tri != no) |
314 | sym->flags |= SYMBOL_WRITE; | 324 | sym->flags |= SYMBOL_WRITE; |
315 | if (!sym_is_choice(sym)) { | 325 | if (!sym_is_choice(sym)) { |
316 | prop = sym_get_default_prop(sym); | 326 | prop = sym_get_default_prop(sym); |
317 | if (prop) { | 327 | if (prop) { |
318 | sym->flags |= SYMBOL_WRITE; | 328 | sym->flags |= SYMBOL_WRITE; |
319 | newval.tri = EXPR_AND(expr_calc_value(prop->expr), | 329 | newval.tri = EXPR_AND(expr_calc_value(prop->expr), |
320 | prop->visible.tri); | 330 | prop->visible.tri); |
321 | } | 331 | } |
322 | } | 332 | } |
323 | calc_newval: | 333 | calc_newval: |
334 | if (sym->dir_dep.tri == no && sym->rev_dep.tri != no) { | ||
335 | fprintf(stderr, "warning: ("); | ||
336 | expr_fprint(sym->rev_dep.expr, stderr); | ||
337 | fprintf(stderr, ") selects %s which has unmet direct dependencies (", | ||
338 | sym->name); | ||
339 | expr_fprint(sym->dir_dep.expr, stderr); | ||
340 | fprintf(stderr, ")\n"); | ||
341 | } | ||
324 | newval.tri = EXPR_OR(newval.tri, sym->rev_dep.tri); | 342 | newval.tri = EXPR_OR(newval.tri, sym->rev_dep.tri); |
325 | } | 343 | } |
326 | if (newval.tri == mod && sym_get_type(sym) == S_BOOLEAN) | 344 | if (newval.tri == mod && sym_get_type(sym) == S_BOOLEAN) |
327 | newval.tri = yes; | 345 | newval.tri = yes; |
328 | break; | 346 | break; |
329 | case S_STRING: | 347 | case S_STRING: |
330 | case S_HEX: | 348 | case S_HEX: |
331 | case S_INT: | 349 | case S_INT: |
332 | if (sym->visible != no) { | 350 | if (sym->visible != no) { |
333 | sym->flags |= SYMBOL_WRITE; | 351 | sym->flags |= SYMBOL_WRITE; |
334 | if (sym_has_value(sym)) { | 352 | if (sym_has_value(sym)) { |
335 | newval.val = sym->def[S_DEF_USER].val; | 353 | newval.val = sym->def[S_DEF_USER].val; |
336 | break; | 354 | break; |
337 | } | 355 | } |
338 | } | 356 | } |
339 | prop = sym_get_default_prop(sym); | 357 | prop = sym_get_default_prop(sym); |
340 | if (prop) { | 358 | if (prop) { |
341 | struct symbol *ds = prop_get_symbol(prop); | 359 | struct symbol *ds = prop_get_symbol(prop); |
342 | if (ds) { | 360 | if (ds) { |
343 | sym->flags |= SYMBOL_WRITE; | 361 | sym->flags |= SYMBOL_WRITE; |
344 | sym_calc_value(ds); | 362 | sym_calc_value(ds); |
345 | newval.val = ds->curr.val; | 363 | newval.val = ds->curr.val; |
346 | } | 364 | } |
347 | } | 365 | } |
348 | break; | 366 | break; |
349 | default: | 367 | default: |
350 | ; | 368 | ; |
351 | } | 369 | } |
352 | 370 | ||
353 | sym->curr = newval; | 371 | sym->curr = newval; |
354 | if (sym_is_choice(sym) && newval.tri == yes) | 372 | if (sym_is_choice(sym) && newval.tri == yes) |
355 | sym->curr.val = sym_calc_choice(sym); | 373 | sym->curr.val = sym_calc_choice(sym); |
356 | sym_validate_range(sym); | 374 | sym_validate_range(sym); |
357 | 375 | ||
358 | if (memcmp(&oldval, &sym->curr, sizeof(oldval))) { | 376 | if (memcmp(&oldval, &sym->curr, sizeof(oldval))) { |
359 | sym_set_changed(sym); | 377 | sym_set_changed(sym); |
360 | if (modules_sym == sym) { | 378 | if (modules_sym == sym) { |
361 | sym_set_all_changed(); | 379 | sym_set_all_changed(); |
362 | modules_val = modules_sym->curr.tri; | 380 | modules_val = modules_sym->curr.tri; |
363 | } | 381 | } |
364 | } | 382 | } |
365 | 383 | ||
366 | if (sym_is_choice(sym)) { | 384 | if (sym_is_choice(sym)) { |
367 | struct symbol *choice_sym; | 385 | struct symbol *choice_sym; |
368 | int flags = sym->flags & (SYMBOL_CHANGED | SYMBOL_WRITE); | 386 | int flags = sym->flags & (SYMBOL_CHANGED | SYMBOL_WRITE); |
369 | 387 | ||
370 | prop = sym_get_choice_prop(sym); | 388 | prop = sym_get_choice_prop(sym); |
371 | expr_list_for_each_sym(prop->expr, e, choice_sym) { | 389 | expr_list_for_each_sym(prop->expr, e, choice_sym) { |
372 | choice_sym->flags |= flags; | 390 | choice_sym->flags |= flags; |
373 | if (flags & SYMBOL_CHANGED) | 391 | if (flags & SYMBOL_CHANGED) |
374 | sym_set_changed(choice_sym); | 392 | sym_set_changed(choice_sym); |
375 | } | 393 | } |
376 | } | 394 | } |
377 | 395 | ||
378 | if (sym->flags & SYMBOL_AUTO) | 396 | if (sym->flags & SYMBOL_AUTO) |
379 | sym->flags &= ~SYMBOL_WRITE; | 397 | sym->flags &= ~SYMBOL_WRITE; |
380 | } | 398 | } |
381 | 399 | ||
382 | void sym_clear_all_valid(void) | 400 | void sym_clear_all_valid(void) |
383 | { | 401 | { |
384 | struct symbol *sym; | 402 | struct symbol *sym; |
385 | int i; | 403 | int i; |
386 | 404 | ||
387 | for_all_symbols(i, sym) | 405 | for_all_symbols(i, sym) |
388 | sym->flags &= ~SYMBOL_VALID; | 406 | sym->flags &= ~SYMBOL_VALID; |
389 | sym_add_change_count(1); | 407 | sym_add_change_count(1); |
390 | if (modules_sym) | 408 | if (modules_sym) |
391 | sym_calc_value(modules_sym); | 409 | sym_calc_value(modules_sym); |
392 | } | 410 | } |
393 | 411 | ||
394 | void sym_set_changed(struct symbol *sym) | 412 | void sym_set_changed(struct symbol *sym) |
395 | { | 413 | { |
396 | struct property *prop; | 414 | struct property *prop; |
397 | 415 | ||
398 | sym->flags |= SYMBOL_CHANGED; | 416 | sym->flags |= SYMBOL_CHANGED; |
399 | for (prop = sym->prop; prop; prop = prop->next) { | 417 | for (prop = sym->prop; prop; prop = prop->next) { |
400 | if (prop->menu) | 418 | if (prop->menu) |
401 | prop->menu->flags |= MENU_CHANGED; | 419 | prop->menu->flags |= MENU_CHANGED; |
402 | } | 420 | } |
403 | } | 421 | } |
404 | 422 | ||
405 | void sym_set_all_changed(void) | 423 | void sym_set_all_changed(void) |
406 | { | 424 | { |
407 | struct symbol *sym; | 425 | struct symbol *sym; |
408 | int i; | 426 | int i; |
409 | 427 | ||
410 | for_all_symbols(i, sym) | 428 | for_all_symbols(i, sym) |
411 | sym_set_changed(sym); | 429 | sym_set_changed(sym); |
412 | } | 430 | } |
413 | 431 | ||
414 | bool sym_tristate_within_range(struct symbol *sym, tristate val) | 432 | bool sym_tristate_within_range(struct symbol *sym, tristate val) |
415 | { | 433 | { |
416 | int type = sym_get_type(sym); | 434 | int type = sym_get_type(sym); |
417 | 435 | ||
418 | if (sym->visible == no) | 436 | if (sym->visible == no) |
419 | return false; | 437 | return false; |
420 | 438 | ||
421 | if (type != S_BOOLEAN && type != S_TRISTATE) | 439 | if (type != S_BOOLEAN && type != S_TRISTATE) |
422 | return false; | 440 | return false; |
423 | 441 | ||
424 | if (type == S_BOOLEAN && val == mod) | 442 | if (type == S_BOOLEAN && val == mod) |
425 | return false; | 443 | return false; |
426 | if (sym->visible <= sym->rev_dep.tri) | 444 | if (sym->visible <= sym->rev_dep.tri) |
427 | return false; | 445 | return false; |
428 | if (sym_is_choice_value(sym) && sym->visible == yes) | 446 | if (sym_is_choice_value(sym) && sym->visible == yes) |
429 | return val == yes; | 447 | return val == yes; |
430 | return val >= sym->rev_dep.tri && val <= sym->visible; | 448 | return val >= sym->rev_dep.tri && val <= sym->visible; |
431 | } | 449 | } |
432 | 450 | ||
433 | bool sym_set_tristate_value(struct symbol *sym, tristate val) | 451 | bool sym_set_tristate_value(struct symbol *sym, tristate val) |
434 | { | 452 | { |
435 | tristate oldval = sym_get_tristate_value(sym); | 453 | tristate oldval = sym_get_tristate_value(sym); |
436 | 454 | ||
437 | if (oldval != val && !sym_tristate_within_range(sym, val)) | 455 | if (oldval != val && !sym_tristate_within_range(sym, val)) |
438 | return false; | 456 | return false; |
439 | 457 | ||
440 | if (!(sym->flags & SYMBOL_DEF_USER)) { | 458 | if (!(sym->flags & SYMBOL_DEF_USER)) { |
441 | sym->flags |= SYMBOL_DEF_USER; | 459 | sym->flags |= SYMBOL_DEF_USER; |
442 | sym_set_changed(sym); | 460 | sym_set_changed(sym); |
443 | } | 461 | } |
444 | /* | 462 | /* |
445 | * setting a choice value also resets the new flag of the choice | 463 | * setting a choice value also resets the new flag of the choice |
446 | * symbol and all other choice values. | 464 | * symbol and all other choice values. |
447 | */ | 465 | */ |
448 | if (sym_is_choice_value(sym) && val == yes) { | 466 | if (sym_is_choice_value(sym) && val == yes) { |
449 | struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym)); | 467 | struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym)); |
450 | struct property *prop; | 468 | struct property *prop; |
451 | struct expr *e; | 469 | struct expr *e; |
452 | 470 | ||
453 | cs->def[S_DEF_USER].val = sym; | 471 | cs->def[S_DEF_USER].val = sym; |
454 | cs->flags |= SYMBOL_DEF_USER; | 472 | cs->flags |= SYMBOL_DEF_USER; |
455 | prop = sym_get_choice_prop(cs); | 473 | prop = sym_get_choice_prop(cs); |
456 | for (e = prop->expr; e; e = e->left.expr) { | 474 | for (e = prop->expr; e; e = e->left.expr) { |
457 | if (e->right.sym->visible != no) | 475 | if (e->right.sym->visible != no) |
458 | e->right.sym->flags |= SYMBOL_DEF_USER; | 476 | e->right.sym->flags |= SYMBOL_DEF_USER; |
459 | } | 477 | } |
460 | } | 478 | } |
461 | 479 | ||
462 | sym->def[S_DEF_USER].tri = val; | 480 | sym->def[S_DEF_USER].tri = val; |
463 | if (oldval != val) | 481 | if (oldval != val) |
464 | sym_clear_all_valid(); | 482 | sym_clear_all_valid(); |
465 | 483 | ||
466 | return true; | 484 | return true; |
467 | } | 485 | } |
468 | 486 | ||
469 | tristate sym_toggle_tristate_value(struct symbol *sym) | 487 | tristate sym_toggle_tristate_value(struct symbol *sym) |
470 | { | 488 | { |
471 | tristate oldval, newval; | 489 | tristate oldval, newval; |
472 | 490 | ||
473 | oldval = newval = sym_get_tristate_value(sym); | 491 | oldval = newval = sym_get_tristate_value(sym); |
474 | do { | 492 | do { |
475 | switch (newval) { | 493 | switch (newval) { |
476 | case no: | 494 | case no: |
477 | newval = mod; | 495 | newval = mod; |
478 | break; | 496 | break; |
479 | case mod: | 497 | case mod: |
480 | newval = yes; | 498 | newval = yes; |
481 | break; | 499 | break; |
482 | case yes: | 500 | case yes: |
483 | newval = no; | 501 | newval = no; |
484 | break; | 502 | break; |
485 | } | 503 | } |
486 | if (sym_set_tristate_value(sym, newval)) | 504 | if (sym_set_tristate_value(sym, newval)) |
487 | break; | 505 | break; |
488 | } while (oldval != newval); | 506 | } while (oldval != newval); |
489 | return newval; | 507 | return newval; |
490 | } | 508 | } |
491 | 509 | ||
492 | bool sym_string_valid(struct symbol *sym, const char *str) | 510 | bool sym_string_valid(struct symbol *sym, const char *str) |
493 | { | 511 | { |
494 | signed char ch; | 512 | signed char ch; |
495 | 513 | ||
496 | switch (sym->type) { | 514 | switch (sym->type) { |
497 | case S_STRING: | 515 | case S_STRING: |
498 | return true; | 516 | return true; |
499 | case S_INT: | 517 | case S_INT: |
500 | ch = *str++; | 518 | ch = *str++; |
501 | if (ch == '-') | 519 | if (ch == '-') |
502 | ch = *str++; | 520 | ch = *str++; |
503 | if (!isdigit(ch)) | 521 | if (!isdigit(ch)) |
504 | return false; | 522 | return false; |
505 | if (ch == '0' && *str != 0) | 523 | if (ch == '0' && *str != 0) |
506 | return false; | 524 | return false; |
507 | while ((ch = *str++)) { | 525 | while ((ch = *str++)) { |
508 | if (!isdigit(ch)) | 526 | if (!isdigit(ch)) |
509 | return false; | 527 | return false; |
510 | } | 528 | } |
511 | return true; | 529 | return true; |
512 | case S_HEX: | 530 | case S_HEX: |
513 | if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) | 531 | if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) |
514 | str += 2; | 532 | str += 2; |
515 | ch = *str++; | 533 | ch = *str++; |
516 | do { | 534 | do { |
517 | if (!isxdigit(ch)) | 535 | if (!isxdigit(ch)) |
518 | return false; | 536 | return false; |
519 | } while ((ch = *str++)); | 537 | } while ((ch = *str++)); |
520 | return true; | 538 | return true; |
521 | case S_BOOLEAN: | 539 | case S_BOOLEAN: |
522 | case S_TRISTATE: | 540 | case S_TRISTATE: |
523 | switch (str[0]) { | 541 | switch (str[0]) { |
524 | case 'y': case 'Y': | 542 | case 'y': case 'Y': |
525 | case 'm': case 'M': | 543 | case 'm': case 'M': |
526 | case 'n': case 'N': | 544 | case 'n': case 'N': |
527 | return true; | 545 | return true; |
528 | } | 546 | } |
529 | return false; | 547 | return false; |
530 | default: | 548 | default: |
531 | return false; | 549 | return false; |
532 | } | 550 | } |
533 | } | 551 | } |
534 | 552 | ||
535 | bool sym_string_within_range(struct symbol *sym, const char *str) | 553 | bool sym_string_within_range(struct symbol *sym, const char *str) |
536 | { | 554 | { |
537 | struct property *prop; | 555 | struct property *prop; |
538 | int val; | 556 | int val; |
539 | 557 | ||
540 | switch (sym->type) { | 558 | switch (sym->type) { |
541 | case S_STRING: | 559 | case S_STRING: |
542 | return sym_string_valid(sym, str); | 560 | return sym_string_valid(sym, str); |
543 | case S_INT: | 561 | case S_INT: |
544 | if (!sym_string_valid(sym, str)) | 562 | if (!sym_string_valid(sym, str)) |
545 | return false; | 563 | return false; |
546 | prop = sym_get_range_prop(sym); | 564 | prop = sym_get_range_prop(sym); |
547 | if (!prop) | 565 | if (!prop) |
548 | return true; | 566 | return true; |
549 | val = strtol(str, NULL, 10); | 567 | val = strtol(str, NULL, 10); |
550 | return val >= sym_get_range_val(prop->expr->left.sym, 10) && | 568 | return val >= sym_get_range_val(prop->expr->left.sym, 10) && |
551 | val <= sym_get_range_val(prop->expr->right.sym, 10); | 569 | val <= sym_get_range_val(prop->expr->right.sym, 10); |
552 | case S_HEX: | 570 | case S_HEX: |
553 | if (!sym_string_valid(sym, str)) | 571 | if (!sym_string_valid(sym, str)) |
554 | return false; | 572 | return false; |
555 | prop = sym_get_range_prop(sym); | 573 | prop = sym_get_range_prop(sym); |
556 | if (!prop) | 574 | if (!prop) |
557 | return true; | 575 | return true; |
558 | val = strtol(str, NULL, 16); | 576 | val = strtol(str, NULL, 16); |
559 | return val >= sym_get_range_val(prop->expr->left.sym, 16) && | 577 | return val >= sym_get_range_val(prop->expr->left.sym, 16) && |
560 | val <= sym_get_range_val(prop->expr->right.sym, 16); | 578 | val <= sym_get_range_val(prop->expr->right.sym, 16); |
561 | case S_BOOLEAN: | 579 | case S_BOOLEAN: |
562 | case S_TRISTATE: | 580 | case S_TRISTATE: |
563 | switch (str[0]) { | 581 | switch (str[0]) { |
564 | case 'y': case 'Y': | 582 | case 'y': case 'Y': |
565 | return sym_tristate_within_range(sym, yes); | 583 | return sym_tristate_within_range(sym, yes); |
566 | case 'm': case 'M': | 584 | case 'm': case 'M': |
567 | return sym_tristate_within_range(sym, mod); | 585 | return sym_tristate_within_range(sym, mod); |
568 | case 'n': case 'N': | 586 | case 'n': case 'N': |
569 | return sym_tristate_within_range(sym, no); | 587 | return sym_tristate_within_range(sym, no); |
570 | } | 588 | } |
571 | return false; | 589 | return false; |
572 | default: | 590 | default: |
573 | return false; | 591 | return false; |
574 | } | 592 | } |
575 | } | 593 | } |
576 | 594 | ||
577 | bool sym_set_string_value(struct symbol *sym, const char *newval) | 595 | bool sym_set_string_value(struct symbol *sym, const char *newval) |
578 | { | 596 | { |
579 | const char *oldval; | 597 | const char *oldval; |
580 | char *val; | 598 | char *val; |
581 | int size; | 599 | int size; |
582 | 600 | ||
583 | switch (sym->type) { | 601 | switch (sym->type) { |
584 | case S_BOOLEAN: | 602 | case S_BOOLEAN: |
585 | case S_TRISTATE: | 603 | case S_TRISTATE: |
586 | switch (newval[0]) { | 604 | switch (newval[0]) { |
587 | case 'y': case 'Y': | 605 | case 'y': case 'Y': |
588 | return sym_set_tristate_value(sym, yes); | 606 | return sym_set_tristate_value(sym, yes); |
589 | case 'm': case 'M': | 607 | case 'm': case 'M': |
590 | return sym_set_tristate_value(sym, mod); | 608 | return sym_set_tristate_value(sym, mod); |
591 | case 'n': case 'N': | 609 | case 'n': case 'N': |
592 | return sym_set_tristate_value(sym, no); | 610 | return sym_set_tristate_value(sym, no); |
593 | } | 611 | } |
594 | return false; | 612 | return false; |
595 | default: | 613 | default: |
596 | ; | 614 | ; |
597 | } | 615 | } |
598 | 616 | ||
599 | if (!sym_string_within_range(sym, newval)) | 617 | if (!sym_string_within_range(sym, newval)) |
600 | return false; | 618 | return false; |
601 | 619 | ||
602 | if (!(sym->flags & SYMBOL_DEF_USER)) { | 620 | if (!(sym->flags & SYMBOL_DEF_USER)) { |
603 | sym->flags |= SYMBOL_DEF_USER; | 621 | sym->flags |= SYMBOL_DEF_USER; |
604 | sym_set_changed(sym); | 622 | sym_set_changed(sym); |
605 | } | 623 | } |
606 | 624 | ||
607 | oldval = sym->def[S_DEF_USER].val; | 625 | oldval = sym->def[S_DEF_USER].val; |
608 | size = strlen(newval) + 1; | 626 | size = strlen(newval) + 1; |
609 | if (sym->type == S_HEX && (newval[0] != '0' || (newval[1] != 'x' && newval[1] != 'X'))) { | 627 | if (sym->type == S_HEX && (newval[0] != '0' || (newval[1] != 'x' && newval[1] != 'X'))) { |
610 | size += 2; | 628 | size += 2; |
611 | sym->def[S_DEF_USER].val = val = malloc(size); | 629 | sym->def[S_DEF_USER].val = val = malloc(size); |
612 | *val++ = '0'; | 630 | *val++ = '0'; |
613 | *val++ = 'x'; | 631 | *val++ = 'x'; |
614 | } else if (!oldval || strcmp(oldval, newval)) | 632 | } else if (!oldval || strcmp(oldval, newval)) |
615 | sym->def[S_DEF_USER].val = val = malloc(size); | 633 | sym->def[S_DEF_USER].val = val = malloc(size); |
616 | else | 634 | else |
617 | return true; | 635 | return true; |
618 | 636 | ||
619 | strcpy(val, newval); | 637 | strcpy(val, newval); |
620 | free((void *)oldval); | 638 | free((void *)oldval); |
621 | sym_clear_all_valid(); | 639 | sym_clear_all_valid(); |
622 | 640 | ||
623 | return true; | 641 | return true; |
624 | } | 642 | } |
625 | 643 | ||
626 | const char *sym_get_string_value(struct symbol *sym) | 644 | const char *sym_get_string_value(struct symbol *sym) |
627 | { | 645 | { |
628 | tristate val; | 646 | tristate val; |
629 | 647 | ||
630 | switch (sym->type) { | 648 | switch (sym->type) { |
631 | case S_BOOLEAN: | 649 | case S_BOOLEAN: |
632 | case S_TRISTATE: | 650 | case S_TRISTATE: |
633 | val = sym_get_tristate_value(sym); | 651 | val = sym_get_tristate_value(sym); |
634 | switch (val) { | 652 | switch (val) { |
635 | case no: | 653 | case no: |
636 | return "n"; | 654 | return "n"; |
637 | case mod: | 655 | case mod: |
638 | return "m"; | 656 | return "m"; |
639 | case yes: | 657 | case yes: |
640 | return "y"; | 658 | return "y"; |
641 | } | 659 | } |
642 | break; | 660 | break; |
643 | default: | 661 | default: |
644 | ; | 662 | ; |
645 | } | 663 | } |
646 | return (const char *)sym->curr.val; | 664 | return (const char *)sym->curr.val; |
647 | } | 665 | } |
648 | 666 | ||
649 | bool sym_is_changable(struct symbol *sym) | 667 | bool sym_is_changable(struct symbol *sym) |
650 | { | 668 | { |
651 | return sym->visible > sym->rev_dep.tri; | 669 | return sym->visible > sym->rev_dep.tri; |
652 | } | 670 | } |
653 | 671 | ||
654 | static unsigned strhash(const char *s) | 672 | static unsigned strhash(const char *s) |
655 | { | 673 | { |
656 | /* fnv32 hash */ | 674 | /* fnv32 hash */ |
657 | unsigned hash = 2166136261U; | 675 | unsigned hash = 2166136261U; |
658 | for (; *s; s++) | 676 | for (; *s; s++) |
659 | hash = (hash ^ *s) * 0x01000193; | 677 | hash = (hash ^ *s) * 0x01000193; |
660 | return hash; | 678 | return hash; |
661 | } | 679 | } |
662 | 680 | ||
663 | struct symbol *sym_lookup(const char *name, int flags) | 681 | struct symbol *sym_lookup(const char *name, int flags) |
664 | { | 682 | { |
665 | struct symbol *symbol; | 683 | struct symbol *symbol; |
666 | char *new_name; | 684 | char *new_name; |
667 | int hash; | 685 | int hash; |
668 | 686 | ||
669 | if (name) { | 687 | if (name) { |
670 | if (name[0] && !name[1]) { | 688 | if (name[0] && !name[1]) { |
671 | switch (name[0]) { | 689 | switch (name[0]) { |
672 | case 'y': return &symbol_yes; | 690 | case 'y': return &symbol_yes; |
673 | case 'm': return &symbol_mod; | 691 | case 'm': return &symbol_mod; |
674 | case 'n': return &symbol_no; | 692 | case 'n': return &symbol_no; |
675 | } | 693 | } |
676 | } | 694 | } |
677 | hash = strhash(name) % SYMBOL_HASHSIZE; | 695 | hash = strhash(name) % SYMBOL_HASHSIZE; |
678 | 696 | ||
679 | for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) { | 697 | for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) { |
680 | if (symbol->name && | 698 | if (symbol->name && |
681 | !strcmp(symbol->name, name) && | 699 | !strcmp(symbol->name, name) && |
682 | (flags ? symbol->flags & flags | 700 | (flags ? symbol->flags & flags |
683 | : !(symbol->flags & (SYMBOL_CONST|SYMBOL_CHOICE)))) | 701 | : !(symbol->flags & (SYMBOL_CONST|SYMBOL_CHOICE)))) |
684 | return symbol; | 702 | return symbol; |
685 | } | 703 | } |
686 | new_name = strdup(name); | 704 | new_name = strdup(name); |
687 | } else { | 705 | } else { |
688 | new_name = NULL; | 706 | new_name = NULL; |
689 | hash = 0; | 707 | hash = 0; |
690 | } | 708 | } |
691 | 709 | ||
692 | symbol = malloc(sizeof(*symbol)); | 710 | symbol = malloc(sizeof(*symbol)); |
693 | memset(symbol, 0, sizeof(*symbol)); | 711 | memset(symbol, 0, sizeof(*symbol)); |
694 | symbol->name = new_name; | 712 | symbol->name = new_name; |
695 | symbol->type = S_UNKNOWN; | 713 | symbol->type = S_UNKNOWN; |
696 | symbol->flags |= flags; | 714 | symbol->flags |= flags; |
697 | 715 | ||
698 | symbol->next = symbol_hash[hash]; | 716 | symbol->next = symbol_hash[hash]; |
699 | symbol_hash[hash] = symbol; | 717 | symbol_hash[hash] = symbol; |
700 | 718 | ||
701 | return symbol; | 719 | return symbol; |
702 | } | 720 | } |
703 | 721 | ||
704 | struct symbol *sym_find(const char *name) | 722 | struct symbol *sym_find(const char *name) |
705 | { | 723 | { |
706 | struct symbol *symbol = NULL; | 724 | struct symbol *symbol = NULL; |
707 | int hash = 0; | 725 | int hash = 0; |
708 | 726 | ||
709 | if (!name) | 727 | if (!name) |
710 | return NULL; | 728 | return NULL; |
711 | 729 | ||
712 | if (name[0] && !name[1]) { | 730 | if (name[0] && !name[1]) { |
713 | switch (name[0]) { | 731 | switch (name[0]) { |
714 | case 'y': return &symbol_yes; | 732 | case 'y': return &symbol_yes; |
715 | case 'm': return &symbol_mod; | 733 | case 'm': return &symbol_mod; |
716 | case 'n': return &symbol_no; | 734 | case 'n': return &symbol_no; |
717 | } | 735 | } |
718 | } | 736 | } |
719 | hash = strhash(name) % SYMBOL_HASHSIZE; | 737 | hash = strhash(name) % SYMBOL_HASHSIZE; |
720 | 738 | ||
721 | for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) { | 739 | for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) { |
722 | if (symbol->name && | 740 | if (symbol->name && |
723 | !strcmp(symbol->name, name) && | 741 | !strcmp(symbol->name, name) && |
724 | !(symbol->flags & SYMBOL_CONST)) | 742 | !(symbol->flags & SYMBOL_CONST)) |
725 | break; | 743 | break; |
726 | } | 744 | } |
727 | 745 | ||
728 | return symbol; | 746 | return symbol; |
729 | } | 747 | } |
730 | 748 | ||
731 | struct symbol **sym_re_search(const char *pattern) | 749 | struct symbol **sym_re_search(const char *pattern) |
732 | { | 750 | { |
733 | struct symbol *sym, **sym_arr = NULL; | 751 | struct symbol *sym, **sym_arr = NULL; |
734 | int i, cnt, size; | 752 | int i, cnt, size; |
735 | regex_t re; | 753 | regex_t re; |
736 | 754 | ||
737 | cnt = size = 0; | 755 | cnt = size = 0; |
738 | /* Skip if empty */ | 756 | /* Skip if empty */ |
739 | if (strlen(pattern) == 0) | 757 | if (strlen(pattern) == 0) |
740 | return NULL; | 758 | return NULL; |
741 | if (regcomp(&re, pattern, REG_EXTENDED|REG_NOSUB|REG_ICASE)) | 759 | if (regcomp(&re, pattern, REG_EXTENDED|REG_NOSUB|REG_ICASE)) |
742 | return NULL; | 760 | return NULL; |
743 | 761 | ||
744 | for_all_symbols(i, sym) { | 762 | for_all_symbols(i, sym) { |
745 | if (sym->flags & SYMBOL_CONST || !sym->name) | 763 | if (sym->flags & SYMBOL_CONST || !sym->name) |
746 | continue; | 764 | continue; |
747 | if (regexec(&re, sym->name, 0, NULL, 0)) | 765 | if (regexec(&re, sym->name, 0, NULL, 0)) |
748 | continue; | 766 | continue; |
749 | if (cnt + 1 >= size) { | 767 | if (cnt + 1 >= size) { |
750 | void *tmp = sym_arr; | 768 | void *tmp = sym_arr; |
751 | size += 16; | 769 | size += 16; |
752 | sym_arr = realloc(sym_arr, size * sizeof(struct symbol *)); | 770 | sym_arr = realloc(sym_arr, size * sizeof(struct symbol *)); |
753 | if (!sym_arr) { | 771 | if (!sym_arr) { |
754 | free(tmp); | 772 | free(tmp); |
755 | return NULL; | 773 | return NULL; |
756 | } | 774 | } |
757 | } | 775 | } |
758 | sym_calc_value(sym); | 776 | sym_calc_value(sym); |
759 | sym_arr[cnt++] = sym; | 777 | sym_arr[cnt++] = sym; |
760 | } | 778 | } |
761 | if (sym_arr) | 779 | if (sym_arr) |
762 | sym_arr[cnt] = NULL; | 780 | sym_arr[cnt] = NULL; |
763 | regfree(&re); | 781 | regfree(&re); |
764 | 782 | ||
765 | return sym_arr; | 783 | return sym_arr; |
766 | } | 784 | } |
767 | 785 | ||
768 | 786 | ||
769 | static struct symbol *sym_check_expr_deps(struct expr *e) | 787 | static struct symbol *sym_check_expr_deps(struct expr *e) |
770 | { | 788 | { |
771 | struct symbol *sym; | 789 | struct symbol *sym; |
772 | 790 | ||
773 | if (!e) | 791 | if (!e) |
774 | return NULL; | 792 | return NULL; |
775 | switch (e->type) { | 793 | switch (e->type) { |
776 | case E_OR: | 794 | case E_OR: |
777 | case E_AND: | 795 | case E_AND: |
778 | sym = sym_check_expr_deps(e->left.expr); | 796 | sym = sym_check_expr_deps(e->left.expr); |
779 | if (sym) | 797 | if (sym) |
780 | return sym; | 798 | return sym; |
781 | return sym_check_expr_deps(e->right.expr); | 799 | return sym_check_expr_deps(e->right.expr); |
782 | case E_NOT: | 800 | case E_NOT: |
783 | return sym_check_expr_deps(e->left.expr); | 801 | return sym_check_expr_deps(e->left.expr); |
784 | case E_EQUAL: | 802 | case E_EQUAL: |
785 | case E_UNEQUAL: | 803 | case E_UNEQUAL: |
786 | sym = sym_check_deps(e->left.sym); | 804 | sym = sym_check_deps(e->left.sym); |
787 | if (sym) | 805 | if (sym) |
788 | return sym; | 806 | return sym; |
789 | return sym_check_deps(e->right.sym); | 807 | return sym_check_deps(e->right.sym); |
790 | case E_SYMBOL: | 808 | case E_SYMBOL: |
791 | return sym_check_deps(e->left.sym); | 809 | return sym_check_deps(e->left.sym); |
792 | default: | 810 | default: |
793 | break; | 811 | break; |
794 | } | 812 | } |
795 | printf("Oops! How to check %d?\n", e->type); | 813 | printf("Oops! How to check %d?\n", e->type); |
796 | return NULL; | 814 | return NULL; |
797 | } | 815 | } |
798 | 816 | ||
799 | /* return NULL when dependencies are OK */ | 817 | /* return NULL when dependencies are OK */ |
800 | static struct symbol *sym_check_sym_deps(struct symbol *sym) | 818 | static struct symbol *sym_check_sym_deps(struct symbol *sym) |
801 | { | 819 | { |
802 | struct symbol *sym2; | 820 | struct symbol *sym2; |
803 | struct property *prop; | 821 | struct property *prop; |
804 | 822 | ||
805 | sym2 = sym_check_expr_deps(sym->rev_dep.expr); | 823 | sym2 = sym_check_expr_deps(sym->rev_dep.expr); |
806 | if (sym2) | 824 | if (sym2) |
807 | return sym2; | 825 | return sym2; |
808 | 826 | ||
809 | for (prop = sym->prop; prop; prop = prop->next) { | 827 | for (prop = sym->prop; prop; prop = prop->next) { |
810 | if (prop->type == P_CHOICE || prop->type == P_SELECT) | 828 | if (prop->type == P_CHOICE || prop->type == P_SELECT) |
811 | continue; | 829 | continue; |
812 | sym2 = sym_check_expr_deps(prop->visible.expr); | 830 | sym2 = sym_check_expr_deps(prop->visible.expr); |
813 | if (sym2) | 831 | if (sym2) |
814 | break; | 832 | break; |
815 | if (prop->type != P_DEFAULT || sym_is_choice(sym)) | 833 | if (prop->type != P_DEFAULT || sym_is_choice(sym)) |
816 | continue; | 834 | continue; |
817 | sym2 = sym_check_expr_deps(prop->expr); | 835 | sym2 = sym_check_expr_deps(prop->expr); |
818 | if (sym2) | 836 | if (sym2) |
819 | break; | 837 | break; |
820 | } | 838 | } |
821 | 839 | ||
822 | return sym2; | 840 | return sym2; |
823 | } | 841 | } |
824 | 842 | ||
825 | static struct symbol *sym_check_choice_deps(struct symbol *choice) | 843 | static struct symbol *sym_check_choice_deps(struct symbol *choice) |
826 | { | 844 | { |
827 | struct symbol *sym, *sym2; | 845 | struct symbol *sym, *sym2; |
828 | struct property *prop; | 846 | struct property *prop; |
829 | struct expr *e; | 847 | struct expr *e; |
830 | 848 | ||
831 | prop = sym_get_choice_prop(choice); | 849 | prop = sym_get_choice_prop(choice); |
832 | expr_list_for_each_sym(prop->expr, e, sym) | 850 | expr_list_for_each_sym(prop->expr, e, sym) |
833 | sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED); | 851 | sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED); |
834 | 852 | ||
835 | choice->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED); | 853 | choice->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED); |
836 | sym2 = sym_check_sym_deps(choice); | 854 | sym2 = sym_check_sym_deps(choice); |
837 | choice->flags &= ~SYMBOL_CHECK; | 855 | choice->flags &= ~SYMBOL_CHECK; |
838 | if (sym2) | 856 | if (sym2) |
839 | goto out; | 857 | goto out; |
840 | 858 | ||
841 | expr_list_for_each_sym(prop->expr, e, sym) { | 859 | expr_list_for_each_sym(prop->expr, e, sym) { |
842 | sym2 = sym_check_sym_deps(sym); | 860 | sym2 = sym_check_sym_deps(sym); |
843 | if (sym2) { | 861 | if (sym2) { |
844 | fprintf(stderr, " -> %s", sym->name); | 862 | fprintf(stderr, " -> %s", sym->name); |
845 | break; | 863 | break; |
846 | } | 864 | } |
847 | } | 865 | } |
848 | out: | 866 | out: |
849 | expr_list_for_each_sym(prop->expr, e, sym) | 867 | expr_list_for_each_sym(prop->expr, e, sym) |
850 | sym->flags &= ~SYMBOL_CHECK; | 868 | sym->flags &= ~SYMBOL_CHECK; |
851 | 869 | ||
852 | if (sym2 && sym_is_choice_value(sym2) && | 870 | if (sym2 && sym_is_choice_value(sym2) && |
853 | prop_get_symbol(sym_get_choice_prop(sym2)) == choice) | 871 | prop_get_symbol(sym_get_choice_prop(sym2)) == choice) |
854 | sym2 = choice; | 872 | sym2 = choice; |
855 | 873 | ||
856 | return sym2; | 874 | return sym2; |
857 | } | 875 | } |
858 | 876 | ||
859 | struct symbol *sym_check_deps(struct symbol *sym) | 877 | struct symbol *sym_check_deps(struct symbol *sym) |
860 | { | 878 | { |
861 | struct symbol *sym2; | 879 | struct symbol *sym2; |
862 | struct property *prop; | 880 | struct property *prop; |
863 | 881 | ||
864 | if (sym->flags & SYMBOL_CHECK) { | 882 | if (sym->flags & SYMBOL_CHECK) { |
865 | fprintf(stderr, "%s:%d:error: found recursive dependency: %s", | 883 | fprintf(stderr, "%s:%d:error: found recursive dependency: %s", |
866 | sym->prop->file->name, sym->prop->lineno, | 884 | sym->prop->file->name, sym->prop->lineno, |
867 | sym->name ? sym->name : "<choice>"); | 885 | sym->name ? sym->name : "<choice>"); |
868 | return sym; | 886 | return sym; |
869 | } | 887 | } |
870 | if (sym->flags & SYMBOL_CHECKED) | 888 | if (sym->flags & SYMBOL_CHECKED) |
871 | return NULL; | 889 | return NULL; |
872 | 890 | ||
873 | if (sym_is_choice_value(sym)) { | 891 | if (sym_is_choice_value(sym)) { |
874 | /* for choice groups start the check with main choice symbol */ | 892 | /* for choice groups start the check with main choice symbol */ |
875 | prop = sym_get_choice_prop(sym); | 893 | prop = sym_get_choice_prop(sym); |
876 | sym2 = sym_check_deps(prop_get_symbol(prop)); | 894 | sym2 = sym_check_deps(prop_get_symbol(prop)); |
877 | } else if (sym_is_choice(sym)) { | 895 | } else if (sym_is_choice(sym)) { |
878 | sym2 = sym_check_choice_deps(sym); | 896 | sym2 = sym_check_choice_deps(sym); |
879 | } else { | 897 | } else { |
880 | sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED); | 898 | sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED); |
881 | sym2 = sym_check_sym_deps(sym); | 899 | sym2 = sym_check_sym_deps(sym); |
882 | sym->flags &= ~SYMBOL_CHECK; | 900 | sym->flags &= ~SYMBOL_CHECK; |
883 | } | 901 | } |
884 | 902 | ||
885 | if (sym2) { | 903 | if (sym2) { |
886 | fprintf(stderr, " -> %s", sym->name ? sym->name : "<choice>"); | 904 | fprintf(stderr, " -> %s", sym->name ? sym->name : "<choice>"); |
887 | if (sym2 == sym) { | 905 | if (sym2 == sym) { |
888 | fprintf(stderr, "\n"); | 906 | fprintf(stderr, "\n"); |
889 | zconfnerrs++; | 907 | zconfnerrs++; |
890 | sym2 = NULL; | 908 | sym2 = NULL; |
891 | } | 909 | } |
892 | } | 910 | } |
893 | 911 | ||
894 | return sym2; | 912 | return sym2; |
895 | } | 913 | } |
896 | 914 | ||
897 | struct property *prop_alloc(enum prop_type type, struct symbol *sym) | 915 | struct property *prop_alloc(enum prop_type type, struct symbol *sym) |
898 | { | 916 | { |
899 | struct property *prop; | 917 | struct property *prop; |
900 | struct property **propp; | 918 | struct property **propp; |
901 | 919 | ||
902 | prop = malloc(sizeof(*prop)); | 920 | prop = malloc(sizeof(*prop)); |
903 | memset(prop, 0, sizeof(*prop)); | 921 | memset(prop, 0, sizeof(*prop)); |
904 | prop->type = type; | 922 | prop->type = type; |
905 | prop->sym = sym; | 923 | prop->sym = sym; |
906 | prop->file = current_file; | 924 | prop->file = current_file; |
907 | prop->lineno = zconf_lineno(); | 925 | prop->lineno = zconf_lineno(); |
908 | 926 | ||
909 | /* append property to the prop list of symbol */ | 927 | /* append property to the prop list of symbol */ |
910 | if (sym) { | 928 | if (sym) { |
911 | for (propp = &sym->prop; *propp; propp = &(*propp)->next) | 929 | for (propp = &sym->prop; *propp; propp = &(*propp)->next) |
912 | ; | 930 | ; |
913 | *propp = prop; | 931 | *propp = prop; |
914 | } | 932 | } |
915 | 933 | ||
916 | return prop; | 934 | return prop; |
917 | } | 935 | } |
918 | 936 | ||
919 | struct symbol *prop_get_symbol(struct property *prop) | 937 | struct symbol *prop_get_symbol(struct property *prop) |
920 | { | 938 | { |
921 | if (prop->expr && (prop->expr->type == E_SYMBOL || | 939 | if (prop->expr && (prop->expr->type == E_SYMBOL || |
922 | prop->expr->type == E_LIST)) | 940 | prop->expr->type == E_LIST)) |
923 | return prop->expr->left.sym; | 941 | return prop->expr->left.sym; |
924 | return NULL; | 942 | return NULL; |
925 | } | 943 | } |
926 | 944 | ||
927 | const char *prop_get_type_name(enum prop_type type) | 945 | const char *prop_get_type_name(enum prop_type type) |
928 | { | 946 | { |
929 | switch (type) { | 947 | switch (type) { |
930 | case P_PROMPT: | 948 | case P_PROMPT: |
931 | return "prompt"; | 949 | return "prompt"; |
932 | case P_ENV: | 950 | case P_ENV: |
933 | return "env"; | 951 | return "env"; |
934 | case P_COMMENT: | 952 | case P_COMMENT: |
935 | return "comment"; | 953 | return "comment"; |
936 | case P_MENU: | 954 | case P_MENU: |
937 | return "menu"; | 955 | return "menu"; |
938 | case P_DEFAULT: | 956 | case P_DEFAULT: |
939 | return "default"; | 957 | return "default"; |
940 | case P_CHOICE: | 958 | case P_CHOICE: |
941 | return "choice"; | 959 | return "choice"; |
942 | case P_SELECT: | 960 | case P_SELECT: |
943 | return "select"; | 961 | return "select"; |
944 | case P_RANGE: | 962 | case P_RANGE: |
945 | return "range"; | 963 | return "range"; |
946 | case P_UNKNOWN: | 964 | case P_UNKNOWN: |
947 | break; | 965 | break; |
948 | } | 966 | } |
949 | return "unknown"; | 967 | return "unknown"; |
950 | } | 968 | } |
951 | 969 | ||
952 | static void prop_add_env(const char *env) | 970 | static void prop_add_env(const char *env) |
953 | { | 971 | { |
954 | struct symbol *sym, *sym2; | 972 | struct symbol *sym, *sym2; |
955 | struct property *prop; | 973 | struct property *prop; |
956 | char *p; | 974 | char *p; |
957 | 975 | ||
958 | sym = current_entry->sym; | 976 | sym = current_entry->sym; |
959 | sym->flags |= SYMBOL_AUTO; | 977 | sym->flags |= SYMBOL_AUTO; |
960 | for_all_properties(sym, prop, P_ENV) { | 978 | for_all_properties(sym, prop, P_ENV) { |
961 | sym2 = prop_get_symbol(prop); | 979 | sym2 = prop_get_symbol(prop); |
962 | if (strcmp(sym2->name, env)) | 980 | if (strcmp(sym2->name, env)) |
963 | menu_warn(current_entry, "redefining environment symbol from %s", | 981 | menu_warn(current_entry, "redefining environment symbol from %s", |
964 | sym2->name); | 982 | sym2->name); |
965 | return; | 983 | return; |
966 | } | 984 | } |
967 | 985 | ||
968 | prop = prop_alloc(P_ENV, sym); | 986 | prop = prop_alloc(P_ENV, sym); |
969 | prop->expr = expr_alloc_symbol(sym_lookup(env, SYMBOL_CONST)); | 987 | prop->expr = expr_alloc_symbol(sym_lookup(env, SYMBOL_CONST)); |
970 | 988 | ||
971 | sym_env_list = expr_alloc_one(E_LIST, sym_env_list); | 989 | sym_env_list = expr_alloc_one(E_LIST, sym_env_list); |
972 | sym_env_list->right.sym = sym; | 990 | sym_env_list->right.sym = sym; |
973 | 991 | ||
974 | p = getenv(env); | 992 | p = getenv(env); |
975 | if (p) | 993 | if (p) |
976 | sym_add_default(sym, p); | 994 | sym_add_default(sym, p); |
977 | else | 995 | else |
978 | menu_warn(current_entry, "environment variable %s undefined", env); | 996 | menu_warn(current_entry, "environment variable %s undefined", env); |
979 | } | 997 | } |
980 | 998 |