Root/
Source at commit 1085 created 13 years 1 month ago. By azimutz, Runaway "min"; fixes build. | |
---|---|
1 | /*␊ |
2 | * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>␊ |
3 | * Released under the terms of the GNU GPL v2.0.␊ |
4 | */␊ |
5 | ␊ |
6 | #include <ctype.h>␊ |
7 | #include <stdlib.h>␊ |
8 | #include <string.h>␊ |
9 | #include <regex.h>␊ |
10 | #include <sys/utsname.h>␊ |
11 | ␊ |
12 | #define LKC_DIRECT_LINK␊ |
13 | #include "lkc.h"␊ |
14 | ␊ |
15 | struct symbol symbol_yes = {␊ |
16 | ␉.name = "y",␊ |
17 | ␉.curr = { "y", yes },␊ |
18 | ␉.flags = SYMBOL_CONST|SYMBOL_VALID,␊ |
19 | }, symbol_mod = {␊ |
20 | ␉.name = "m",␊ |
21 | ␉.curr = { "m", mod },␊ |
22 | ␉.flags = SYMBOL_CONST|SYMBOL_VALID,␊ |
23 | }, symbol_no = {␊ |
24 | ␉.name = "n",␊ |
25 | ␉.curr = { "n", no },␊ |
26 | ␉.flags = SYMBOL_CONST|SYMBOL_VALID,␊ |
27 | }, symbol_empty = {␊ |
28 | ␉.name = "",␊ |
29 | ␉.curr = { "", no },␊ |
30 | ␉.flags = SYMBOL_VALID,␊ |
31 | };␊ |
32 | ␊ |
33 | struct symbol *sym_defconfig_list;␊ |
34 | struct symbol *modules_sym;␊ |
35 | tristate modules_val;␊ |
36 | ␊ |
37 | struct expr *sym_env_list;␊ |
38 | ␊ |
39 | static void sym_add_default(struct symbol *sym, const char *def)␊ |
40 | {␊ |
41 | ␉struct property *prop = prop_alloc(P_DEFAULT, sym);␊ |
42 | ␊ |
43 | ␉prop->expr = expr_alloc_symbol(sym_lookup(def, SYMBOL_CONST));␊ |
44 | }␊ |
45 | ␊ |
46 | void sym_init(void)␊ |
47 | {␊ |
48 | ␉struct symbol *sym;␊ |
49 | ␉struct utsname uts;␊ |
50 | ␉static bool inited = false;␊ |
51 | ␊ |
52 | ␉if (inited)␊ |
53 | ␉␉return;␊ |
54 | ␉inited = true;␊ |
55 | ␊ |
56 | ␉uname(&uts);␊ |
57 | ␊ |
58 | ␉sym = sym_lookup("UNAME_RELEASE", 0);␊ |
59 | ␉sym->type = S_STRING;␊ |
60 | ␉sym->flags |= SYMBOL_AUTO;␊ |
61 | ␉sym_add_default(sym, uts.release);␊ |
62 | }␊ |
63 | ␊ |
64 | enum symbol_type sym_get_type(struct symbol *sym)␊ |
65 | {␊ |
66 | ␉enum symbol_type type = sym->type;␊ |
67 | ␊ |
68 | ␉if (type == S_TRISTATE) {␊ |
69 | ␉␉if (sym_is_choice_value(sym) && sym->visible == yes)␊ |
70 | ␉␉␉type = S_BOOLEAN;␊ |
71 | ␉␉else if (modules_val == no)␊ |
72 | ␉␉␉type = S_BOOLEAN;␊ |
73 | ␉}␊ |
74 | ␉return type;␊ |
75 | }␊ |
76 | ␊ |
77 | const char *sym_type_name(enum symbol_type type)␊ |
78 | {␊ |
79 | ␉switch (type) {␊ |
80 | ␉case S_BOOLEAN:␊ |
81 | ␉␉return "boolean";␊ |
82 | ␉case S_TRISTATE:␊ |
83 | ␉␉return "tristate";␊ |
84 | ␉case S_INT:␊ |
85 | ␉␉return "integer";␊ |
86 | ␉case S_HEX:␊ |
87 | ␉␉return "hex";␊ |
88 | ␉case S_STRING:␊ |
89 | ␉␉return "string";␊ |
90 | ␉case S_UNKNOWN:␊ |
91 | ␉␉return "unknown";␊ |
92 | ␉case S_OTHER:␊ |
93 | ␉␉break;␊ |
94 | ␉}␊ |
95 | ␉return "???";␊ |
96 | }␊ |
97 | ␊ |
98 | struct property *sym_get_choice_prop(struct symbol *sym)␊ |
99 | {␊ |
100 | ␉struct property *prop;␊ |
101 | ␊ |
102 | ␉for_all_choices(sym, prop)␊ |
103 | ␉␉return prop;␊ |
104 | ␉return NULL;␊ |
105 | }␊ |
106 | ␊ |
107 | struct property *sym_get_env_prop(struct symbol *sym)␊ |
108 | {␊ |
109 | ␉struct property *prop;␊ |
110 | ␊ |
111 | ␉for_all_properties(sym, prop, P_ENV)␊ |
112 | ␉␉return prop;␊ |
113 | ␉return NULL;␊ |
114 | }␊ |
115 | ␊ |
116 | struct property *sym_get_default_prop(struct symbol *sym)␊ |
117 | {␊ |
118 | ␉struct property *prop;␊ |
119 | ␊ |
120 | ␉for_all_defaults(sym, prop) {␊ |
121 | ␉␉prop->visible.tri = expr_calc_value(prop->visible.expr);␊ |
122 | ␉␉if (prop->visible.tri != no)␊ |
123 | ␉␉␉return prop;␊ |
124 | ␉}␊ |
125 | ␉return NULL;␊ |
126 | }␊ |
127 | ␊ |
128 | static struct property *sym_get_range_prop(struct symbol *sym)␊ |
129 | {␊ |
130 | ␉struct property *prop;␊ |
131 | ␊ |
132 | ␉for_all_properties(sym, prop, P_RANGE) {␊ |
133 | ␉␉prop->visible.tri = expr_calc_value(prop->visible.expr);␊ |
134 | ␉␉if (prop->visible.tri != no)␊ |
135 | ␉␉␉return prop;␊ |
136 | ␉}␊ |
137 | ␉return NULL;␊ |
138 | }␊ |
139 | ␊ |
140 | static int sym_get_range_val(struct symbol *sym, int base)␊ |
141 | {␊ |
142 | ␉sym_calc_value(sym);␊ |
143 | ␉switch (sym->type) {␊ |
144 | ␉case S_INT:␊ |
145 | ␉␉base = 10;␊ |
146 | ␉␉break;␊ |
147 | ␉case S_HEX:␊ |
148 | ␉␉base = 16;␊ |
149 | ␉␉break;␊ |
150 | ␉default:␊ |
151 | ␉␉break;␊ |
152 | ␉}␊ |
153 | ␉return strtol(sym->curr.val, NULL, base);␊ |
154 | }␊ |
155 | ␊ |
156 | static void sym_validate_range(struct symbol *sym)␊ |
157 | {␊ |
158 | ␉struct property *prop;␊ |
159 | ␉int base, val, val2;␊ |
160 | ␉char str[64];␊ |
161 | ␊ |
162 | ␉switch (sym->type) {␊ |
163 | ␉case S_INT:␊ |
164 | ␉␉base = 10;␊ |
165 | ␉␉break;␊ |
166 | ␉case S_HEX:␊ |
167 | ␉␉base = 16;␊ |
168 | ␉␉break;␊ |
169 | ␉default:␊ |
170 | ␉␉return;␊ |
171 | ␉}␊ |
172 | ␉prop = sym_get_range_prop(sym);␊ |
173 | ␉if (!prop)␊ |
174 | ␉␉return;␊ |
175 | ␉val = strtol(sym->curr.val, NULL, base);␊ |
176 | ␉val2 = sym_get_range_val(prop->expr->left.sym, base);␊ |
177 | ␉if (val >= val2) {␊ |
178 | ␉␉val2 = sym_get_range_val(prop->expr->right.sym, base);␊ |
179 | ␉␉if (val <= val2)␊ |
180 | ␉␉␉return;␊ |
181 | ␉}␊ |
182 | ␉if (sym->type == S_INT)␊ |
183 | ␉␉sprintf(str, "%d", val2);␊ |
184 | ␉else␊ |
185 | ␉␉sprintf(str, "0x%x", val2);␊ |
186 | ␉sym->curr.val = strdup(str);␊ |
187 | }␊ |
188 | ␊ |
189 | static void sym_calc_visibility(struct symbol *sym)␊ |
190 | {␊ |
191 | ␉struct property *prop;␊ |
192 | ␉tristate tri;␊ |
193 | ␊ |
194 | ␉/* any prompt visible? */␊ |
195 | ␉tri = no;␊ |
196 | ␉for_all_prompts(sym, prop) {␊ |
197 | ␉␉prop->visible.tri = expr_calc_value(prop->visible.expr);␊ |
198 | ␉␉tri = EXPR_OR(tri, prop->visible.tri);␊ |
199 | ␉}␊ |
200 | ␉if (tri == mod && (sym->type != S_TRISTATE || modules_val == no))␊ |
201 | ␉␉tri = yes;␊ |
202 | ␉if (sym->visible != tri) {␊ |
203 | ␉␉sym->visible = tri;␊ |
204 | ␉␉sym_set_changed(sym);␊ |
205 | ␉}␊ |
206 | ␉if (sym_is_choice_value(sym))␊ |
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 | ␉}␊ |
218 | ␉tri = no;␊ |
219 | ␉if (sym->rev_dep.expr)␊ |
220 | ␉␉tri = expr_calc_value(sym->rev_dep.expr);␊ |
221 | ␉if (tri == mod && sym_get_type(sym) == S_BOOLEAN)␊ |
222 | ␉␉tri = yes;␊ |
223 | ␉if (sym->rev_dep.tri != tri) {␊ |
224 | ␉␉sym->rev_dep.tri = tri;␊ |
225 | ␉␉sym_set_changed(sym);␊ |
226 | ␉}␊ |
227 | }␊ |
228 | ␊ |
229 | /*␊ |
230 | * Find the default symbol for a choice.␊ |
231 | * First try the default values for the choice symbol␊ |
232 | * Next locate the first visible choice value␊ |
233 | * Return NULL if none was found␊ |
234 | */␊ |
235 | struct symbol *sym_choice_default(struct symbol *sym)␊ |
236 | {␊ |
237 | ␉struct symbol *def_sym;␊ |
238 | ␉struct property *prop;␊ |
239 | ␉struct expr *e;␊ |
240 | ␊ |
241 | ␉/* any of the defaults visible? */␊ |
242 | ␉for_all_defaults(sym, prop) {␊ |
243 | ␉␉prop->visible.tri = expr_calc_value(prop->visible.expr);␊ |
244 | ␉␉if (prop->visible.tri == no)␊ |
245 | ␉␉␉continue;␊ |
246 | ␉␉def_sym = prop_get_symbol(prop);␊ |
247 | ␉␉if (def_sym->visible != no)␊ |
248 | ␉␉␉return def_sym;␊ |
249 | ␉}␊ |
250 | ␊ |
251 | ␉/* just get the first visible value */␊ |
252 | ␉prop = sym_get_choice_prop(sym);␊ |
253 | ␉expr_list_for_each_sym(prop->expr, e, def_sym)␊ |
254 | ␉␉if (def_sym->visible != no)␊ |
255 | ␉␉␉return def_sym;␊ |
256 | ␊ |
257 | ␉/* failed to locate any defaults */␊ |
258 | ␉return NULL;␊ |
259 | }␊ |
260 | ␊ |
261 | static struct symbol *sym_calc_choice(struct symbol *sym)␊ |
262 | {␊ |
263 | ␉struct symbol *def_sym;␊ |
264 | ␉struct property *prop;␊ |
265 | ␉struct expr *e;␊ |
266 | ␊ |
267 | ␉/* first calculate all choice values' visibilities */␊ |
268 | ␉prop = sym_get_choice_prop(sym);␊ |
269 | ␉expr_list_for_each_sym(prop->expr, e, def_sym)␊ |
270 | ␉␉sym_calc_visibility(def_sym);␊ |
271 | ␊ |
272 | ␉/* is the user choice visible? */␊ |
273 | ␉def_sym = sym->def[S_DEF_USER].val;␊ |
274 | ␉if (def_sym && def_sym->visible != no)␊ |
275 | ␉␉return def_sym;␊ |
276 | ␊ |
277 | ␉def_sym = sym_choice_default(sym);␊ |
278 | ␊ |
279 | ␉if (def_sym == NULL)␊ |
280 | ␉␉/* no choice? reset tristate value */␊ |
281 | ␉␉sym->curr.tri = no;␊ |
282 | ␊ |
283 | ␉return def_sym;␊ |
284 | }␊ |
285 | ␊ |
286 | void sym_calc_value(struct symbol *sym)␊ |
287 | {␊ |
288 | ␉struct symbol_value newval, oldval;␊ |
289 | ␉struct property *prop;␊ |
290 | ␉struct expr *e;␊ |
291 | ␊ |
292 | ␉if (!sym)␊ |
293 | ␉␉return;␊ |
294 | ␊ |
295 | ␉if (sym->flags & SYMBOL_VALID)␊ |
296 | ␉␉return;␊ |
297 | ␉sym->flags |= SYMBOL_VALID;␊ |
298 | ␊ |
299 | ␉oldval = sym->curr;␊ |
300 | ␊ |
301 | ␉switch (sym->type) {␊ |
302 | ␉case S_INT:␊ |
303 | ␉case S_HEX:␊ |
304 | ␉case S_STRING:␊ |
305 | ␉␉newval = symbol_empty.curr;␊ |
306 | ␉␉break;␊ |
307 | ␉case S_BOOLEAN:␊ |
308 | ␉case S_TRISTATE:␊ |
309 | ␉␉newval = symbol_no.curr;␊ |
310 | ␉␉break;␊ |
311 | ␉default:␊ |
312 | ␉␉sym->curr.val = sym->name;␊ |
313 | ␉␉sym->curr.tri = no;␊ |
314 | ␉␉return;␊ |
315 | ␉}␊ |
316 | ␉if (!sym_is_choice_value(sym))␊ |
317 | ␉␉sym->flags &= ~SYMBOL_WRITE;␊ |
318 | ␊ |
319 | ␉sym_calc_visibility(sym);␊ |
320 | ␊ |
321 | ␉/* set default if recursively called */␊ |
322 | ␉sym->curr = newval;␊ |
323 | ␊ |
324 | ␉switch (sym_get_type(sym)) {␊ |
325 | ␉case S_BOOLEAN:␊ |
326 | ␉case S_TRISTATE:␊ |
327 | ␉␉if (sym_is_choice_value(sym) && sym->visible == yes) {␊ |
328 | ␉␉␉prop = sym_get_choice_prop(sym);␊ |
329 | ␉␉␉newval.tri = (prop_get_symbol(prop)->curr.val == sym) ? yes : no;␊ |
330 | ␉␉} else {␊ |
331 | ␉␉␉if (sym->visible != no) {␊ |
332 | ␉␉␉␉/* if the symbol is visible use the user value␊ |
333 | ␉␉␉␉ * if available, otherwise try the default value␊ |
334 | ␉␉␉␉ */␊ |
335 | ␉␉␉␉sym->flags |= SYMBOL_WRITE;␊ |
336 | ␉␉␉␉if (sym_has_value(sym)) {␊ |
337 | ␉␉␉␉␉newval.tri = EXPR_AND(sym->def[S_DEF_USER].tri,␊ |
338 | ␉␉␉␉␉␉␉ sym->visible);␊ |
339 | ␉␉␉␉␉goto calc_newval;␊ |
340 | ␉␉␉␉}␊ |
341 | ␉␉␉}␊ |
342 | ␉␉␉if (sym->rev_dep.tri != no)␊ |
343 | ␉␉␉␉sym->flags |= SYMBOL_WRITE;␊ |
344 | ␉␉␉if (!sym_is_choice(sym)) {␊ |
345 | ␉␉␉␉prop = sym_get_default_prop(sym);␊ |
346 | ␉␉␉␉if (prop) {␊ |
347 | ␉␉␉␉␉sym->flags |= SYMBOL_WRITE;␊ |
348 | ␉␉␉␉␉newval.tri = EXPR_AND(expr_calc_value(prop->expr),␊ |
349 | ␉␉␉␉␉␉␉ prop->visible.tri);␊ |
350 | ␉␉␉␉}␊ |
351 | ␉␉␉}␊ |
352 | ␉␉calc_newval:␊ |
353 | ␉␉␉if (sym->dir_dep.tri == no && sym->rev_dep.tri != no) {␊ |
354 | ␉␉␉␉struct expr *e;␊ |
355 | ␉␉␉␉e = expr_simplify_unmet_dep(sym->rev_dep.expr,␊ |
356 | ␉␉␉␉ sym->dir_dep.expr);␊ |
357 | ␉␉␉␉fprintf(stderr, "warning: (");␊ |
358 | ␉␉␉␉expr_fprint(e, stderr);␊ |
359 | ␉␉␉␉fprintf(stderr, ") selects %s which has unmet direct dependencies (",␊ |
360 | ␉␉␉␉␉sym->name);␊ |
361 | ␉␉␉␉expr_fprint(sym->dir_dep.expr, stderr);␊ |
362 | ␉␉␉␉fprintf(stderr, ")\n");␊ |
363 | ␉␉␉␉expr_free(e);␊ |
364 | ␉␉␉}␊ |
365 | ␉␉␉newval.tri = EXPR_OR(newval.tri, sym->rev_dep.tri);␊ |
366 | ␉␉}␊ |
367 | ␉␉if (newval.tri == mod && sym_get_type(sym) == S_BOOLEAN)␊ |
368 | ␉␉␉newval.tri = yes;␊ |
369 | ␉␉break;␊ |
370 | ␉case S_STRING:␊ |
371 | ␉case S_HEX:␊ |
372 | ␉case S_INT:␊ |
373 | ␉␉if (sym->visible != no) {␊ |
374 | ␉␉␉sym->flags |= SYMBOL_WRITE;␊ |
375 | ␉␉␉if (sym_has_value(sym)) {␊ |
376 | ␉␉␉␉newval.val = sym->def[S_DEF_USER].val;␊ |
377 | ␉␉␉␉break;␊ |
378 | ␉␉␉}␊ |
379 | ␉␉}␊ |
380 | ␉␉prop = sym_get_default_prop(sym);␊ |
381 | ␉␉if (prop) {␊ |
382 | ␉␉␉struct symbol *ds = prop_get_symbol(prop);␊ |
383 | ␉␉␉if (ds) {␊ |
384 | ␉␉␉␉sym->flags |= SYMBOL_WRITE;␊ |
385 | ␉␉␉␉sym_calc_value(ds);␊ |
386 | ␉␉␉␉newval.val = ds->curr.val;␊ |
387 | ␉␉␉}␊ |
388 | ␉␉}␊ |
389 | ␉␉break;␊ |
390 | ␉default:␊ |
391 | ␉␉;␊ |
392 | ␉}␊ |
393 | ␊ |
394 | ␉sym->curr = newval;␊ |
395 | ␉if (sym_is_choice(sym) && newval.tri == yes)␊ |
396 | ␉␉sym->curr.val = sym_calc_choice(sym);␊ |
397 | ␉sym_validate_range(sym);␊ |
398 | ␊ |
399 | ␉if (memcmp(&oldval, &sym->curr, sizeof(oldval))) {␊ |
400 | ␉␉sym_set_changed(sym);␊ |
401 | ␉␉if (modules_sym == sym) {␊ |
402 | ␉␉␉sym_set_all_changed();␊ |
403 | ␉␉␉modules_val = modules_sym->curr.tri;␊ |
404 | ␉␉}␊ |
405 | ␉}␊ |
406 | ␊ |
407 | ␉if (sym_is_choice(sym)) {␊ |
408 | ␉␉struct symbol *choice_sym;␊ |
409 | ␊ |
410 | ␉␉prop = sym_get_choice_prop(sym);␊ |
411 | ␉␉expr_list_for_each_sym(prop->expr, e, choice_sym) {␊ |
412 | ␉␉␉if ((sym->flags & SYMBOL_WRITE) &&␊ |
413 | ␉␉␉ choice_sym->visible != no)␊ |
414 | ␉␉␉␉choice_sym->flags |= SYMBOL_WRITE;␊ |
415 | ␉␉␉if (sym->flags & SYMBOL_CHANGED)␊ |
416 | ␉␉␉␉sym_set_changed(choice_sym);␊ |
417 | ␉␉}␊ |
418 | ␉}␊ |
419 | ␊ |
420 | ␉if (sym->flags & SYMBOL_AUTO)␊ |
421 | ␉␉sym->flags &= ~SYMBOL_WRITE;␊ |
422 | }␊ |
423 | ␊ |
424 | void sym_clear_all_valid(void)␊ |
425 | {␊ |
426 | ␉struct symbol *sym;␊ |
427 | ␉int i;␊ |
428 | ␊ |
429 | ␉for_all_symbols(i, sym)␊ |
430 | ␉␉sym->flags &= ~SYMBOL_VALID;␊ |
431 | ␉sym_add_change_count(1);␊ |
432 | ␉if (modules_sym)␊ |
433 | ␉␉sym_calc_value(modules_sym);␊ |
434 | }␊ |
435 | ␊ |
436 | void sym_set_changed(struct symbol *sym)␊ |
437 | {␊ |
438 | ␉struct property *prop;␊ |
439 | ␊ |
440 | ␉sym->flags |= SYMBOL_CHANGED;␊ |
441 | ␉for (prop = sym->prop; prop; prop = prop->next) {␊ |
442 | ␉␉if (prop->menu)␊ |
443 | ␉␉␉prop->menu->flags |= MENU_CHANGED;␊ |
444 | ␉}␊ |
445 | }␊ |
446 | ␊ |
447 | void sym_set_all_changed(void)␊ |
448 | {␊ |
449 | ␉struct symbol *sym;␊ |
450 | ␉int i;␊ |
451 | ␊ |
452 | ␉for_all_symbols(i, sym)␊ |
453 | ␉␉sym_set_changed(sym);␊ |
454 | }␊ |
455 | ␊ |
456 | bool sym_tristate_within_range(struct symbol *sym, tristate val)␊ |
457 | {␊ |
458 | ␉int type = sym_get_type(sym);␊ |
459 | ␊ |
460 | ␉if (sym->visible == no)␊ |
461 | ␉␉return false;␊ |
462 | ␊ |
463 | ␉if (type != S_BOOLEAN && type != S_TRISTATE)␊ |
464 | ␉␉return false;␊ |
465 | ␊ |
466 | ␉if (type == S_BOOLEAN && val == mod)␊ |
467 | ␉␉return false;␊ |
468 | ␉if (sym->visible <= sym->rev_dep.tri)␊ |
469 | ␉␉return false;␊ |
470 | ␉if (sym_is_choice_value(sym) && sym->visible == yes)␊ |
471 | ␉␉return val == yes;␊ |
472 | ␉return val >= sym->rev_dep.tri && val <= sym->visible;␊ |
473 | }␊ |
474 | ␊ |
475 | bool sym_set_tristate_value(struct symbol *sym, tristate val)␊ |
476 | {␊ |
477 | ␉tristate oldval = sym_get_tristate_value(sym);␊ |
478 | ␊ |
479 | ␉if (oldval != val && !sym_tristate_within_range(sym, val))␊ |
480 | ␉␉return false;␊ |
481 | ␊ |
482 | ␉if (!(sym->flags & SYMBOL_DEF_USER)) {␊ |
483 | ␉␉sym->flags |= SYMBOL_DEF_USER;␊ |
484 | ␉␉sym_set_changed(sym);␊ |
485 | ␉}␊ |
486 | ␉/*␊ |
487 | ␉ * setting a choice value also resets the new flag of the choice␊ |
488 | ␉ * symbol and all other choice values.␊ |
489 | ␉ */␊ |
490 | ␉if (sym_is_choice_value(sym) && val == yes) {␊ |
491 | ␉␉struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));␊ |
492 | ␉␉struct property *prop;␊ |
493 | ␉␉struct expr *e;␊ |
494 | ␊ |
495 | ␉␉cs->def[S_DEF_USER].val = sym;␊ |
496 | ␉␉cs->flags |= SYMBOL_DEF_USER;␊ |
497 | ␉␉prop = sym_get_choice_prop(cs);␊ |
498 | ␉␉for (e = prop->expr; e; e = e->left.expr) {␊ |
499 | ␉␉␉if (e->right.sym->visible != no)␊ |
500 | ␉␉␉␉e->right.sym->flags |= SYMBOL_DEF_USER;␊ |
501 | ␉␉}␊ |
502 | ␉}␊ |
503 | ␊ |
504 | ␉sym->def[S_DEF_USER].tri = val;␊ |
505 | ␉if (oldval != val)␊ |
506 | ␉␉sym_clear_all_valid();␊ |
507 | ␊ |
508 | ␉return true;␊ |
509 | }␊ |
510 | ␊ |
511 | tristate sym_toggle_tristate_value(struct symbol *sym)␊ |
512 | {␊ |
513 | ␉tristate oldval, newval;␊ |
514 | ␊ |
515 | ␉oldval = newval = sym_get_tristate_value(sym);␊ |
516 | ␉do {␊ |
517 | ␉␉switch (newval) {␊ |
518 | ␉␉case no:␊ |
519 | ␉␉␉newval = mod;␊ |
520 | ␉␉␉break;␊ |
521 | ␉␉case mod:␊ |
522 | ␉␉␉newval = yes;␊ |
523 | ␉␉␉break;␊ |
524 | ␉␉case yes:␊ |
525 | ␉␉␉newval = no;␊ |
526 | ␉␉␉break;␊ |
527 | ␉␉}␊ |
528 | ␉␉if (sym_set_tristate_value(sym, newval))␊ |
529 | ␉␉␉break;␊ |
530 | ␉} while (oldval != newval);␊ |
531 | ␉return newval;␊ |
532 | }␊ |
533 | ␊ |
534 | bool sym_string_valid(struct symbol *sym, const char *str)␊ |
535 | {␊ |
536 | ␉signed char ch;␊ |
537 | ␊ |
538 | ␉switch (sym->type) {␊ |
539 | ␉case S_STRING:␊ |
540 | ␉␉return true;␊ |
541 | ␉case S_INT:␊ |
542 | ␉␉ch = *str++;␊ |
543 | ␉␉if (ch == '-')␊ |
544 | ␉␉␉ch = *str++;␊ |
545 | ␉␉if (!isdigit(ch))␊ |
546 | ␉␉␉return false;␊ |
547 | ␉␉if (ch == '0' && *str != 0)␊ |
548 | ␉␉␉return false;␊ |
549 | ␉␉while ((ch = *str++)) {␊ |
550 | ␉␉␉if (!isdigit(ch))␊ |
551 | ␉␉␉␉return false;␊ |
552 | ␉␉}␊ |
553 | ␉␉return true;␊ |
554 | ␉case S_HEX:␊ |
555 | ␉␉if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))␊ |
556 | ␉␉␉str += 2;␊ |
557 | ␉␉ch = *str++;␊ |
558 | ␉␉do {␊ |
559 | ␉␉␉if (!isxdigit(ch))␊ |
560 | ␉␉␉␉return false;␊ |
561 | ␉␉} while ((ch = *str++));␊ |
562 | ␉␉return true;␊ |
563 | ␉case S_BOOLEAN:␊ |
564 | ␉case S_TRISTATE:␊ |
565 | ␉␉switch (str[0]) {␊ |
566 | ␉␉case 'y': case 'Y':␊ |
567 | ␉␉case 'm': case 'M':␊ |
568 | ␉␉case 'n': case 'N':␊ |
569 | ␉␉␉return true;␊ |
570 | ␉␉}␊ |
571 | ␉␉return false;␊ |
572 | ␉default:␊ |
573 | ␉␉return false;␊ |
574 | ␉}␊ |
575 | }␊ |
576 | ␊ |
577 | bool sym_string_within_range(struct symbol *sym, const char *str)␊ |
578 | {␊ |
579 | ␉struct property *prop;␊ |
580 | ␉int val;␊ |
581 | ␊ |
582 | ␉switch (sym->type) {␊ |
583 | ␉case S_STRING:␊ |
584 | ␉␉return sym_string_valid(sym, str);␊ |
585 | ␉case S_INT:␊ |
586 | ␉␉if (!sym_string_valid(sym, str))␊ |
587 | ␉␉␉return false;␊ |
588 | ␉␉prop = sym_get_range_prop(sym);␊ |
589 | ␉␉if (!prop)␊ |
590 | ␉␉␉return true;␊ |
591 | ␉␉val = strtol(str, NULL, 10);␊ |
592 | ␉␉return val >= sym_get_range_val(prop->expr->left.sym, 10) &&␊ |
593 | ␉␉ val <= sym_get_range_val(prop->expr->right.sym, 10);␊ |
594 | ␉case S_HEX:␊ |
595 | ␉␉if (!sym_string_valid(sym, str))␊ |
596 | ␉␉␉return false;␊ |
597 | ␉␉prop = sym_get_range_prop(sym);␊ |
598 | ␉␉if (!prop)␊ |
599 | ␉␉␉return true;␊ |
600 | ␉␉val = strtol(str, NULL, 16);␊ |
601 | ␉␉return val >= sym_get_range_val(prop->expr->left.sym, 16) &&␊ |
602 | ␉␉ val <= sym_get_range_val(prop->expr->right.sym, 16);␊ |
603 | ␉case S_BOOLEAN:␊ |
604 | ␉case S_TRISTATE:␊ |
605 | ␉␉switch (str[0]) {␊ |
606 | ␉␉case 'y': case 'Y':␊ |
607 | ␉␉␉return sym_tristate_within_range(sym, yes);␊ |
608 | ␉␉case 'm': case 'M':␊ |
609 | ␉␉␉return sym_tristate_within_range(sym, mod);␊ |
610 | ␉␉case 'n': case 'N':␊ |
611 | ␉␉␉return sym_tristate_within_range(sym, no);␊ |
612 | ␉␉}␊ |
613 | ␉␉return false;␊ |
614 | ␉default:␊ |
615 | ␉␉return false;␊ |
616 | ␉}␊ |
617 | }␊ |
618 | ␊ |
619 | bool sym_set_string_value(struct symbol *sym, const char *newval)␊ |
620 | {␊ |
621 | ␉const char *oldval;␊ |
622 | ␉char *val;␊ |
623 | ␉int size;␊ |
624 | ␊ |
625 | ␉switch (sym->type) {␊ |
626 | ␉case S_BOOLEAN:␊ |
627 | ␉case S_TRISTATE:␊ |
628 | ␉␉switch (newval[0]) {␊ |
629 | ␉␉case 'y': case 'Y':␊ |
630 | ␉␉␉return sym_set_tristate_value(sym, yes);␊ |
631 | ␉␉case 'm': case 'M':␊ |
632 | ␉␉␉return sym_set_tristate_value(sym, mod);␊ |
633 | ␉␉case 'n': case 'N':␊ |
634 | ␉␉␉return sym_set_tristate_value(sym, no);␊ |
635 | ␉␉}␊ |
636 | ␉␉return false;␊ |
637 | ␉default:␊ |
638 | ␉␉;␊ |
639 | ␉}␊ |
640 | ␊ |
641 | ␉if (!sym_string_within_range(sym, newval))␊ |
642 | ␉␉return false;␊ |
643 | ␊ |
644 | ␉if (!(sym->flags & SYMBOL_DEF_USER)) {␊ |
645 | ␉␉sym->flags |= SYMBOL_DEF_USER;␊ |
646 | ␉␉sym_set_changed(sym);␊ |
647 | ␉}␊ |
648 | ␊ |
649 | ␉oldval = sym->def[S_DEF_USER].val;␊ |
650 | ␉size = strlen(newval) + 1;␊ |
651 | ␉if (sym->type == S_HEX && (newval[0] != '0' || (newval[1] != 'x' && newval[1] != 'X'))) {␊ |
652 | ␉␉size += 2;␊ |
653 | ␉␉sym->def[S_DEF_USER].val = val = malloc(size);␊ |
654 | ␉␉*val++ = '0';␊ |
655 | ␉␉*val++ = 'x';␊ |
656 | ␉} else if (!oldval || strcmp(oldval, newval))␊ |
657 | ␉␉sym->def[S_DEF_USER].val = val = malloc(size);␊ |
658 | ␉else␊ |
659 | ␉␉return true;␊ |
660 | ␊ |
661 | ␉strcpy(val, newval);␊ |
662 | ␉free((void *)oldval);␊ |
663 | ␉sym_clear_all_valid();␊ |
664 | ␊ |
665 | ␉return true;␊ |
666 | }␊ |
667 | ␊ |
668 | /*␊ |
669 | * Find the default value associated to a symbol.␊ |
670 | * For tristate symbol handle the modules=n case␊ |
671 | * in which case "m" becomes "y".␊ |
672 | * If the symbol does not have any default then fallback␊ |
673 | * to the fixed default values.␊ |
674 | */␊ |
675 | const char *sym_get_string_default(struct symbol *sym)␊ |
676 | {␊ |
677 | ␉struct property *prop;␊ |
678 | ␉struct symbol *ds;␊ |
679 | ␉const char *str;␊ |
680 | ␉tristate val;␊ |
681 | ␊ |
682 | ␉sym_calc_visibility(sym);␊ |
683 | ␉sym_calc_value(modules_sym);␊ |
684 | ␉val = symbol_no.curr.tri;␊ |
685 | ␉str = symbol_empty.curr.val;␊ |
686 | ␊ |
687 | ␉/* If symbol has a default value look it up */␊ |
688 | ␉prop = sym_get_default_prop(sym);␊ |
689 | ␉if (prop != NULL) {␊ |
690 | ␉␉switch (sym->type) {␊ |
691 | ␉␉case S_BOOLEAN:␊ |
692 | ␉␉case S_TRISTATE:␊ |
693 | ␉␉␉/* The visibility may limit the value from yes => mod */␊ |
694 | ␉␉␉val = EXPR_AND(expr_calc_value(prop->expr), prop->visible.tri);␊ |
695 | ␉␉␉break;␊ |
696 | ␉␉default:␊ |
697 | ␉␉␉/*␊ |
698 | ␉␉␉ * The following fails to handle the situation␊ |
699 | ␉␉␉ * where a default value is further limited by␊ |
700 | ␉␉␉ * the valid range.␊ |
701 | ␉␉␉ */␊ |
702 | ␉␉␉ds = prop_get_symbol(prop);␊ |
703 | ␉␉␉if (ds != NULL) {␊ |
704 | ␉␉␉␉sym_calc_value(ds);␊ |
705 | ␉␉␉␉str = (const char *)ds->curr.val;␊ |
706 | ␉␉␉}␊ |
707 | ␉␉}␊ |
708 | ␉}␊ |
709 | ␊ |
710 | ␉/* Handle select statements */␊ |
711 | ␉val = EXPR_OR(val, sym->rev_dep.tri);␊ |
712 | ␊ |
713 | ␉/* transpose mod to yes if modules are not enabled */␊ |
714 | ␉if (val == mod)␊ |
715 | ␉␉if (!sym_is_choice_value(sym) && modules_sym->curr.tri == no)␊ |
716 | ␉␉␉val = yes;␊ |
717 | ␊ |
718 | ␉/* transpose mod to yes if type is bool */␊ |
719 | ␉if (sym->type == S_BOOLEAN && val == mod)␊ |
720 | ␉␉val = yes;␊ |
721 | ␊ |
722 | ␉switch (sym->type) {␊ |
723 | ␉case S_BOOLEAN:␊ |
724 | ␉case S_TRISTATE:␊ |
725 | ␉␉switch (val) {␊ |
726 | ␉␉case no: return "n";␊ |
727 | ␉␉case mod: return "m";␊ |
728 | ␉␉case yes: return "y";␊ |
729 | ␉␉}␊ |
730 | ␉case S_INT:␊ |
731 | ␉case S_HEX:␊ |
732 | ␉␉return str;␊ |
733 | ␉case S_STRING:␊ |
734 | ␉␉return str;␊ |
735 | ␉case S_OTHER:␊ |
736 | ␉case S_UNKNOWN:␊ |
737 | ␉␉break;␊ |
738 | ␉}␊ |
739 | ␉return "";␊ |
740 | }␊ |
741 | ␊ |
742 | const char *sym_get_string_value(struct symbol *sym)␊ |
743 | {␊ |
744 | ␉tristate val;␊ |
745 | ␊ |
746 | ␉switch (sym->type) {␊ |
747 | ␉case S_BOOLEAN:␊ |
748 | ␉case S_TRISTATE:␊ |
749 | ␉␉val = sym_get_tristate_value(sym);␊ |
750 | ␉␉switch (val) {␊ |
751 | ␉␉case no:␊ |
752 | ␉␉␉return "n";␊ |
753 | ␉␉case mod:␊ |
754 | ␉␉␉return "m";␊ |
755 | ␉␉case yes:␊ |
756 | ␉␉␉return "y";␊ |
757 | ␉␉}␊ |
758 | ␉␉break;␊ |
759 | ␉default:␊ |
760 | ␉␉;␊ |
761 | ␉}␊ |
762 | ␉return (const char *)sym->curr.val;␊ |
763 | }␊ |
764 | ␊ |
765 | bool sym_is_changable(struct symbol *sym)␊ |
766 | {␊ |
767 | ␉return sym->visible > sym->rev_dep.tri;␊ |
768 | }␊ |
769 | ␊ |
770 | static unsigned strhash(const char *s)␊ |
771 | {␊ |
772 | ␉/* fnv32 hash */␊ |
773 | ␉unsigned hash = 2166136261U;␊ |
774 | ␉for (; *s; s++)␊ |
775 | ␉␉hash = (hash ^ *s) * 0x01000193;␊ |
776 | ␉return hash;␊ |
777 | }␊ |
778 | ␊ |
779 | struct symbol *sym_lookup(const char *name, int flags)␊ |
780 | {␊ |
781 | ␉struct symbol *symbol;␊ |
782 | ␉char *new_name;␊ |
783 | ␉int hash;␊ |
784 | ␊ |
785 | ␉if (name) {␊ |
786 | ␉␉if (name[0] && !name[1]) {␊ |
787 | ␉␉␉switch (name[0]) {␊ |
788 | ␉␉␉case 'y': return &symbol_yes;␊ |
789 | ␉␉␉case 'm': return &symbol_mod;␊ |
790 | ␉␉␉case 'n': return &symbol_no;␊ |
791 | ␉␉␉}␊ |
792 | ␉␉}␊ |
793 | ␉␉hash = strhash(name) % SYMBOL_HASHSIZE;␊ |
794 | ␊ |
795 | ␉␉for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {␊ |
796 | ␉␉␉if (symbol->name &&␊ |
797 | ␉␉␉ !strcmp(symbol->name, name) &&␊ |
798 | ␉␉␉ (flags ? symbol->flags & flags␊ |
799 | ␉␉␉␉ : !(symbol->flags & (SYMBOL_CONST|SYMBOL_CHOICE))))␊ |
800 | ␉␉␉␉return symbol;␊ |
801 | ␉␉}␊ |
802 | ␉␉new_name = strdup(name);␊ |
803 | ␉} else {␊ |
804 | ␉␉new_name = NULL;␊ |
805 | ␉␉hash = 0;␊ |
806 | ␉}␊ |
807 | ␊ |
808 | ␉symbol = malloc(sizeof(*symbol));␊ |
809 | ␉memset(symbol, 0, sizeof(*symbol));␊ |
810 | ␉symbol->name = new_name;␊ |
811 | ␉symbol->type = S_UNKNOWN;␊ |
812 | ␉symbol->flags |= flags;␊ |
813 | ␊ |
814 | ␉symbol->next = symbol_hash[hash];␊ |
815 | ␉symbol_hash[hash] = symbol;␊ |
816 | ␊ |
817 | ␉return symbol;␊ |
818 | }␊ |
819 | ␊ |
820 | struct symbol *sym_find(const char *name)␊ |
821 | {␊ |
822 | ␉struct symbol *symbol = NULL;␊ |
823 | ␉int hash = 0;␊ |
824 | ␊ |
825 | ␉if (!name)␊ |
826 | ␉␉return NULL;␊ |
827 | ␊ |
828 | ␉if (name[0] && !name[1]) {␊ |
829 | ␉␉switch (name[0]) {␊ |
830 | ␉␉case 'y': return &symbol_yes;␊ |
831 | ␉␉case 'm': return &symbol_mod;␊ |
832 | ␉␉case 'n': return &symbol_no;␊ |
833 | ␉␉}␊ |
834 | ␉}␊ |
835 | ␉hash = strhash(name) % SYMBOL_HASHSIZE;␊ |
836 | ␊ |
837 | ␉for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {␊ |
838 | ␉␉if (symbol->name &&␊ |
839 | ␉␉ !strcmp(symbol->name, name) &&␊ |
840 | ␉␉ !(symbol->flags & SYMBOL_CONST))␊ |
841 | ␉␉␉␉break;␊ |
842 | ␉}␊ |
843 | ␊ |
844 | ␉return symbol;␊ |
845 | }␊ |
846 | ␊ |
847 | /*␊ |
848 | * Expand symbol's names embedded in the string given in argument. Symbols'␊ |
849 | * name to be expanded shall be prefixed by a '$'. Unknown symbol expands to␊ |
850 | * the empty string.␊ |
851 | */␊ |
852 | const char *sym_expand_string_value(const char *in)␊ |
853 | {␊ |
854 | ␉const char *src;␊ |
855 | ␉char *res;␊ |
856 | ␉size_t reslen;␊ |
857 | ␊ |
858 | ␉reslen = strlen(in) + 1;␊ |
859 | ␉res = malloc(reslen);␊ |
860 | ␉res[0] = '\0';␊ |
861 | ␊ |
862 | ␉while ((src = strchr(in, '$'))) {␊ |
863 | ␉␉char *p, name[SYMBOL_MAXLENGTH];␊ |
864 | ␉␉const char *symval = "";␊ |
865 | ␉␉struct symbol *sym;␊ |
866 | ␉␉size_t newlen;␊ |
867 | ␊ |
868 | ␉␉strncat(res, in, src - in);␊ |
869 | ␉␉src++;␊ |
870 | ␊ |
871 | ␉␉p = name;␊ |
872 | ␉␉while (isalnum(*src) || *src == '_')␊ |
873 | ␉␉␉*p++ = *src++;␊ |
874 | ␉␉*p = '\0';␊ |
875 | ␊ |
876 | ␉␉sym = sym_find(name);␊ |
877 | ␉␉if (sym != NULL) {␊ |
878 | ␉␉␉sym_calc_value(sym);␊ |
879 | ␉␉␉symval = sym_get_string_value(sym);␊ |
880 | ␉␉}␊ |
881 | ␊ |
882 | ␉␉newlen = strlen(res) + strlen(symval) + strlen(src) + 1;␊ |
883 | ␉␉if (newlen > reslen) {␊ |
884 | ␉␉␉reslen = newlen;␊ |
885 | ␉␉␉res = realloc(res, reslen);␊ |
886 | ␉␉}␊ |
887 | ␊ |
888 | ␉␉strcat(res, symval);␊ |
889 | ␉␉in = src;␊ |
890 | ␉}␊ |
891 | ␉strcat(res, in);␊ |
892 | ␊ |
893 | ␉return res;␊ |
894 | }␊ |
895 | ␊ |
896 | struct symbol **sym_re_search(const char *pattern)␊ |
897 | {␊ |
898 | ␉struct symbol *sym, **sym_arr = NULL;␊ |
899 | ␉int i, cnt, size;␊ |
900 | ␉regex_t re;␊ |
901 | ␊ |
902 | ␉cnt = size = 0;␊ |
903 | ␉/* Skip if empty */␊ |
904 | ␉if (strlen(pattern) == 0)␊ |
905 | ␉␉return NULL;␊ |
906 | ␉if (regcomp(&re, pattern, REG_EXTENDED|REG_NOSUB|REG_ICASE))␊ |
907 | ␉␉return NULL;␊ |
908 | ␊ |
909 | ␉for_all_symbols(i, sym) {␊ |
910 | ␉␉if (sym->flags & SYMBOL_CONST || !sym->name)␊ |
911 | ␉␉␉continue;␊ |
912 | ␉␉if (regexec(&re, sym->name, 0, NULL, 0))␊ |
913 | ␉␉␉continue;␊ |
914 | ␉␉if (cnt + 1 >= size) {␊ |
915 | ␉␉␉void *tmp = sym_arr;␊ |
916 | ␉␉␉size += 16;␊ |
917 | ␉␉␉sym_arr = realloc(sym_arr, size * sizeof(struct symbol *));␊ |
918 | ␉␉␉if (!sym_arr) {␊ |
919 | ␉␉␉␉free(tmp);␊ |
920 | ␉␉␉␉return NULL;␊ |
921 | ␉␉␉}␊ |
922 | ␉␉}␊ |
923 | ␉␉sym_calc_value(sym);␊ |
924 | ␉␉sym_arr[cnt++] = sym;␊ |
925 | ␉}␊ |
926 | ␉if (sym_arr)␊ |
927 | ␉␉sym_arr[cnt] = NULL;␊ |
928 | ␉regfree(&re);␊ |
929 | ␊ |
930 | ␉return sym_arr;␊ |
931 | }␊ |
932 | ␊ |
933 | /*␊ |
934 | * When we check for recursive dependencies we use a stack to save␊ |
935 | * current state so we can print out relevant info to user.␊ |
936 | * The entries are located on the call stack so no need to free memory.␊ |
937 | * Note inser() remove() must always match to properly clear the stack.␊ |
938 | */␊ |
939 | static struct dep_stack {␊ |
940 | ␉struct dep_stack *prev, *next;␊ |
941 | ␉struct symbol *sym;␊ |
942 | ␉struct property *prop;␊ |
943 | ␉struct expr *expr;␊ |
944 | } *check_top;␊ |
945 | ␊ |
946 | static void dep_stack_insert(struct dep_stack *stack, struct symbol *sym)␊ |
947 | {␊ |
948 | ␉memset(stack, 0, sizeof(*stack));␊ |
949 | ␉if (check_top)␊ |
950 | ␉␉check_top->next = stack;␊ |
951 | ␉stack->prev = check_top;␊ |
952 | ␉stack->sym = sym;␊ |
953 | ␉check_top = stack;␊ |
954 | }␊ |
955 | ␊ |
956 | static void dep_stack_remove(void)␊ |
957 | {␊ |
958 | ␉check_top = check_top->prev;␊ |
959 | ␉if (check_top)␊ |
960 | ␉␉check_top->next = NULL;␊ |
961 | }␊ |
962 | ␊ |
963 | /*␊ |
964 | * Called when we have detected a recursive dependency.␊ |
965 | * check_top point to the top of the stact so we use␊ |
966 | * the ->prev pointer to locate the bottom of the stack.␊ |
967 | */␊ |
968 | static void sym_check_print_recursive(struct symbol *last_sym)␊ |
969 | {␊ |
970 | ␉struct dep_stack *stack;␊ |
971 | ␉struct symbol *sym, *next_sym;␊ |
972 | ␉struct menu *menu = NULL;␊ |
973 | ␉struct property *prop;␊ |
974 | ␉struct dep_stack cv_stack;␊ |
975 | ␊ |
976 | ␉if (sym_is_choice_value(last_sym)) {␊ |
977 | ␉␉dep_stack_insert(&cv_stack, last_sym);␊ |
978 | ␉␉last_sym = prop_get_symbol(sym_get_choice_prop(last_sym));␊ |
979 | ␉}␊ |
980 | ␊ |
981 | ␉for (stack = check_top; stack != NULL; stack = stack->prev)␊ |
982 | ␉␉if (stack->sym == last_sym)␊ |
983 | ␉␉␉break;␊ |
984 | ␉if (!stack) {␊ |
985 | ␉␉fprintf(stderr, "unexpected recursive dependency error\n");␊ |
986 | ␉␉return;␊ |
987 | ␉}␊ |
988 | ␊ |
989 | ␉for (; stack; stack = stack->next) {␊ |
990 | ␉␉sym = stack->sym;␊ |
991 | ␉␉next_sym = stack->next ? stack->next->sym : last_sym;␊ |
992 | ␉␉prop = stack->prop;␊ |
993 | ␉␉if (prop == NULL)␊ |
994 | ␉␉␉prop = stack->sym->prop;␊ |
995 | ␊ |
996 | ␉␉/* for choice values find the menu entry (used below) */␊ |
997 | ␉␉if (sym_is_choice(sym) || sym_is_choice_value(sym)) {␊ |
998 | ␉␉␉for (prop = sym->prop; prop; prop = prop->next) {␊ |
999 | ␉␉␉␉menu = prop->menu;␊ |
1000 | ␉␉␉␉if (prop->menu)␊ |
1001 | ␉␉␉␉␉break;␊ |
1002 | ␉␉␉}␊ |
1003 | ␉␉}␊ |
1004 | ␉␉if (stack->sym == last_sym)␊ |
1005 | ␉␉␉fprintf(stderr, "%s:%d:error: recursive dependency detected!\n",␊ |
1006 | ␉␉␉␉prop->file->name, prop->lineno);␊ |
1007 | ␉␉if (stack->expr) {␊ |
1008 | ␉␉␉fprintf(stderr, "%s:%d:\tsymbol %s %s value contains %s\n",␊ |
1009 | ␉␉␉␉prop->file->name, prop->lineno,␊ |
1010 | ␉␉␉␉sym->name ? sym->name : "<choice>",␊ |
1011 | ␉␉␉␉prop_get_type_name(prop->type),␊ |
1012 | ␉␉␉␉next_sym->name ? next_sym->name : "<choice>");␊ |
1013 | ␉␉} else if (stack->prop) {␊ |
1014 | ␉␉␉fprintf(stderr, "%s:%d:\tsymbol %s depends on %s\n",␊ |
1015 | ␉␉␉␉prop->file->name, prop->lineno,␊ |
1016 | ␉␉␉␉sym->name ? sym->name : "<choice>",␊ |
1017 | ␉␉␉␉next_sym->name ? next_sym->name : "<choice>");␊ |
1018 | ␉␉} else if (sym_is_choice(sym)) {␊ |
1019 | ␉␉␉fprintf(stderr, "%s:%d:\tchoice %s contains symbol %s\n",␊ |
1020 | ␉␉␉␉menu->file->name, menu->lineno,␊ |
1021 | ␉␉␉␉sym->name ? sym->name : "<choice>",␊ |
1022 | ␉␉␉␉next_sym->name ? next_sym->name : "<choice>");␊ |
1023 | ␉␉} else if (sym_is_choice_value(sym)) {␊ |
1024 | ␉␉␉fprintf(stderr, "%s:%d:\tsymbol %s is part of choice %s\n",␊ |
1025 | ␉␉␉␉menu->file->name, menu->lineno,␊ |
1026 | ␉␉␉␉sym->name ? sym->name : "<choice>",␊ |
1027 | ␉␉␉␉next_sym->name ? next_sym->name : "<choice>");␊ |
1028 | ␉␉} else {␊ |
1029 | ␉␉␉fprintf(stderr, "%s:%d:\tsymbol %s is selected by %s\n",␊ |
1030 | ␉␉␉␉prop->file->name, prop->lineno,␊ |
1031 | ␉␉␉␉sym->name ? sym->name : "<choice>",␊ |
1032 | ␉␉␉␉next_sym->name ? next_sym->name : "<choice>");␊ |
1033 | ␉␉}␊ |
1034 | ␉}␊ |
1035 | ␊ |
1036 | ␉if (check_top == &cv_stack)␊ |
1037 | ␉␉dep_stack_remove();␊ |
1038 | }␊ |
1039 | ␊ |
1040 | static struct symbol *sym_check_expr_deps(struct expr *e)␊ |
1041 | {␊ |
1042 | ␉struct symbol *sym;␊ |
1043 | ␊ |
1044 | ␉if (!e)␊ |
1045 | ␉␉return NULL;␊ |
1046 | ␉switch (e->type) {␊ |
1047 | ␉case E_OR:␊ |
1048 | ␉case E_AND:␊ |
1049 | ␉␉sym = sym_check_expr_deps(e->left.expr);␊ |
1050 | ␉␉if (sym)␊ |
1051 | ␉␉␉return sym;␊ |
1052 | ␉␉return sym_check_expr_deps(e->right.expr);␊ |
1053 | ␉case E_NOT:␊ |
1054 | ␉␉return sym_check_expr_deps(e->left.expr);␊ |
1055 | ␉case E_EQUAL:␊ |
1056 | ␉case E_UNEQUAL:␊ |
1057 | ␉␉sym = sym_check_deps(e->left.sym);␊ |
1058 | ␉␉if (sym)␊ |
1059 | ␉␉␉return sym;␊ |
1060 | ␉␉return sym_check_deps(e->right.sym);␊ |
1061 | ␉case E_SYMBOL:␊ |
1062 | ␉␉return sym_check_deps(e->left.sym);␊ |
1063 | ␉default:␊ |
1064 | ␉␉break;␊ |
1065 | ␉}␊ |
1066 | ␉printf("Oops! How to check %d?\n", e->type);␊ |
1067 | ␉return NULL;␊ |
1068 | }␊ |
1069 | ␊ |
1070 | /* return NULL when dependencies are OK */␊ |
1071 | static struct symbol *sym_check_sym_deps(struct symbol *sym)␊ |
1072 | {␊ |
1073 | ␉struct symbol *sym2;␊ |
1074 | ␉struct property *prop;␊ |
1075 | ␉struct dep_stack stack;␊ |
1076 | ␊ |
1077 | ␉dep_stack_insert(&stack, sym);␊ |
1078 | ␊ |
1079 | ␉sym2 = sym_check_expr_deps(sym->rev_dep.expr);␊ |
1080 | ␉if (sym2)␊ |
1081 | ␉␉goto out;␊ |
1082 | ␊ |
1083 | ␉for (prop = sym->prop; prop; prop = prop->next) {␊ |
1084 | ␉␉if (prop->type == P_CHOICE || prop->type == P_SELECT)␊ |
1085 | ␉␉␉continue;␊ |
1086 | ␉␉stack.prop = prop;␊ |
1087 | ␉␉sym2 = sym_check_expr_deps(prop->visible.expr);␊ |
1088 | ␉␉if (sym2)␊ |
1089 | ␉␉␉break;␊ |
1090 | ␉␉if (prop->type != P_DEFAULT || sym_is_choice(sym))␊ |
1091 | ␉␉␉continue;␊ |
1092 | ␉␉stack.expr = prop->expr;␊ |
1093 | ␉␉sym2 = sym_check_expr_deps(prop->expr);␊ |
1094 | ␉␉if (sym2)␊ |
1095 | ␉␉␉break;␊ |
1096 | ␉␉stack.expr = NULL;␊ |
1097 | ␉}␊ |
1098 | ␊ |
1099 | out:␊ |
1100 | ␉dep_stack_remove();␊ |
1101 | ␊ |
1102 | ␉return sym2;␊ |
1103 | }␊ |
1104 | ␊ |
1105 | static struct symbol *sym_check_choice_deps(struct symbol *choice)␊ |
1106 | {␊ |
1107 | ␉struct symbol *sym, *sym2;␊ |
1108 | ␉struct property *prop;␊ |
1109 | ␉struct expr *e;␊ |
1110 | ␉struct dep_stack stack;␊ |
1111 | ␊ |
1112 | ␉dep_stack_insert(&stack, choice);␊ |
1113 | ␊ |
1114 | ␉prop = sym_get_choice_prop(choice);␊ |
1115 | ␉expr_list_for_each_sym(prop->expr, e, sym)␊ |
1116 | ␉␉sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);␊ |
1117 | ␊ |
1118 | ␉choice->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);␊ |
1119 | ␉sym2 = sym_check_sym_deps(choice);␊ |
1120 | ␉choice->flags &= ~SYMBOL_CHECK;␊ |
1121 | ␉if (sym2)␊ |
1122 | ␉␉goto out;␊ |
1123 | ␊ |
1124 | ␉expr_list_for_each_sym(prop->expr, e, sym) {␊ |
1125 | ␉␉sym2 = sym_check_sym_deps(sym);␊ |
1126 | ␉␉if (sym2)␊ |
1127 | ␉␉␉break;␊ |
1128 | ␉}␊ |
1129 | out:␊ |
1130 | ␉expr_list_for_each_sym(prop->expr, e, sym)␊ |
1131 | ␉␉sym->flags &= ~SYMBOL_CHECK;␊ |
1132 | ␊ |
1133 | ␉if (sym2 && sym_is_choice_value(sym2) &&␊ |
1134 | ␉ prop_get_symbol(sym_get_choice_prop(sym2)) == choice)␊ |
1135 | ␉␉sym2 = choice;␊ |
1136 | ␊ |
1137 | ␉dep_stack_remove();␊ |
1138 | ␊ |
1139 | ␉return sym2;␊ |
1140 | }␊ |
1141 | ␊ |
1142 | struct symbol *sym_check_deps(struct symbol *sym)␊ |
1143 | {␊ |
1144 | ␉struct symbol *sym2;␊ |
1145 | ␉struct property *prop;␊ |
1146 | ␊ |
1147 | ␉if (sym->flags & SYMBOL_CHECK) {␊ |
1148 | ␉␉sym_check_print_recursive(sym);␊ |
1149 | ␉␉return sym;␊ |
1150 | ␉}␊ |
1151 | ␉if (sym->flags & SYMBOL_CHECKED)␊ |
1152 | ␉␉return NULL;␊ |
1153 | ␊ |
1154 | ␉if (sym_is_choice_value(sym)) {␊ |
1155 | ␉␉struct dep_stack stack;␊ |
1156 | ␊ |
1157 | ␉␉/* for choice groups start the check with main choice symbol */␊ |
1158 | ␉␉dep_stack_insert(&stack, sym);␊ |
1159 | ␉␉prop = sym_get_choice_prop(sym);␊ |
1160 | ␉␉sym2 = sym_check_deps(prop_get_symbol(prop));␊ |
1161 | ␉␉dep_stack_remove();␊ |
1162 | ␉} else if (sym_is_choice(sym)) {␊ |
1163 | ␉␉sym2 = sym_check_choice_deps(sym);␊ |
1164 | ␉} else {␊ |
1165 | ␉␉sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);␊ |
1166 | ␉␉sym2 = sym_check_sym_deps(sym);␊ |
1167 | ␉␉sym->flags &= ~SYMBOL_CHECK;␊ |
1168 | ␉}␊ |
1169 | ␊ |
1170 | ␉if (sym2 && sym2 == sym)␊ |
1171 | ␉␉sym2 = NULL;␊ |
1172 | ␊ |
1173 | ␉return sym2;␊ |
1174 | }␊ |
1175 | ␊ |
1176 | struct property *prop_alloc(enum prop_type type, struct symbol *sym)␊ |
1177 | {␊ |
1178 | ␉struct property *prop;␊ |
1179 | ␉struct property **propp;␊ |
1180 | ␊ |
1181 | ␉prop = malloc(sizeof(*prop));␊ |
1182 | ␉memset(prop, 0, sizeof(*prop));␊ |
1183 | ␉prop->type = type;␊ |
1184 | ␉prop->sym = sym;␊ |
1185 | ␉prop->file = current_file;␊ |
1186 | ␉prop->lineno = zconf_lineno();␊ |
1187 | ␊ |
1188 | ␉/* append property to the prop list of symbol */␊ |
1189 | ␉if (sym) {␊ |
1190 | ␉␉for (propp = &sym->prop; *propp; propp = &(*propp)->next)␊ |
1191 | ␉␉␉;␊ |
1192 | ␉␉*propp = prop;␊ |
1193 | ␉}␊ |
1194 | ␊ |
1195 | ␉return prop;␊ |
1196 | }␊ |
1197 | ␊ |
1198 | struct symbol *prop_get_symbol(struct property *prop)␊ |
1199 | {␊ |
1200 | ␉if (prop->expr && (prop->expr->type == E_SYMBOL ||␊ |
1201 | ␉␉␉ prop->expr->type == E_LIST))␊ |
1202 | ␉␉return prop->expr->left.sym;␊ |
1203 | ␉return NULL;␊ |
1204 | }␊ |
1205 | ␊ |
1206 | const char *prop_get_type_name(enum prop_type type)␊ |
1207 | {␊ |
1208 | ␉switch (type) {␊ |
1209 | ␉case P_PROMPT:␊ |
1210 | ␉␉return "prompt";␊ |
1211 | ␉case P_ENV:␊ |
1212 | ␉␉return "env";␊ |
1213 | ␉case P_COMMENT:␊ |
1214 | ␉␉return "comment";␊ |
1215 | ␉case P_MENU:␊ |
1216 | ␉␉return "menu";␊ |
1217 | ␉case P_DEFAULT:␊ |
1218 | ␉␉return "default";␊ |
1219 | ␉case P_CHOICE:␊ |
1220 | ␉␉return "choice";␊ |
1221 | ␉case P_SELECT:␊ |
1222 | ␉␉return "select";␊ |
1223 | ␉case P_RANGE:␊ |
1224 | ␉␉return "range";␊ |
1225 | ␉case P_SYMBOL:␊ |
1226 | ␉␉return "symbol";␊ |
1227 | ␉case P_UNKNOWN:␊ |
1228 | ␉␉break;␊ |
1229 | ␉}␊ |
1230 | ␉return "unknown";␊ |
1231 | }␊ |
1232 |