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