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_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
33struct symbol *sym_defconfig_list;
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->def[S_DEF_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->def[S_DEF_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->def[S_DEF_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			sym_set_all_changed();
359			modules_val = modules_sym->curr.tri;
360		}
361	}
362
363	if (sym_is_choice(sym)) {
364		int flags = sym->flags & (SYMBOL_CHANGED | SYMBOL_WRITE);
365		prop = sym_get_choice_prop(sym);
366		for (e = prop->expr; e; e = e->left.expr) {
367			e->right.sym->flags |= flags;
368			if (flags & SYMBOL_CHANGED)
369				sym_set_changed(e->right.sym);
370		}
371	}
372}
373
374void sym_clear_all_valid(void)
375{
376	struct symbol *sym;
377	int i;
378
379	for_all_symbols(i, sym)
380		sym->flags &= ~SYMBOL_VALID;
381	sym_add_change_count(1);
382	if (modules_sym)
383		sym_calc_value(modules_sym);
384}
385
386void sym_set_changed(struct symbol *sym)
387{
388	struct property *prop;
389
390	sym->flags |= SYMBOL_CHANGED;
391	for (prop = sym->prop; prop; prop = prop->next) {
392		if (prop->menu)
393			prop->menu->flags |= MENU_CHANGED;
394	}
395}
396
397void sym_set_all_changed(void)
398{
399	struct symbol *sym;
400	int i;
401
402	for_all_symbols(i, sym)
403		sym_set_changed(sym);
404}
405
406bool sym_tristate_within_range(struct symbol *sym, tristate val)
407{
408	int type = sym_get_type(sym);
409
410	if (sym->visible == no)
411		return false;
412
413	if (type != S_BOOLEAN && type != S_TRISTATE)
414		return false;
415
416	if (type == S_BOOLEAN && val == mod)
417		return false;
418	if (sym->visible <= sym->rev_dep.tri)
419		return false;
420	if (sym_is_choice_value(sym) && sym->visible == yes)
421		return val == yes;
422	return val >= sym->rev_dep.tri && val <= sym->visible;
423}
424
425bool sym_set_tristate_value(struct symbol *sym, tristate val)
426{
427	tristate oldval = sym_get_tristate_value(sym);
428
429	if (oldval != val && !sym_tristate_within_range(sym, val))
430		return false;
431
432	if (!(sym->flags & SYMBOL_DEF_USER)) {
433		sym->flags |= SYMBOL_DEF_USER;
434		sym_set_changed(sym);
435	}
436	/*
437	 * setting a choice value also resets the new flag of the choice
438	 * symbol and all other choice values.
439	 */
440	if (sym_is_choice_value(sym) && val == yes) {
441		struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
442		struct property *prop;
443		struct expr *e;
444
445		cs->def[S_DEF_USER].val = sym;
446		cs->flags |= SYMBOL_DEF_USER;
447		prop = sym_get_choice_prop(cs);
448		for (e = prop->expr; e; e = e->left.expr) {
449			if (e->right.sym->visible != no)
450				e->right.sym->flags |= SYMBOL_DEF_USER;
451		}
452	}
453
454	sym->def[S_DEF_USER].tri = val;
455	if (oldval != val)
456		sym_clear_all_valid();
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_DEF_USER)) {
595		sym->flags |= SYMBOL_DEF_USER;
596		sym_set_changed(sym);
597	}
598
599	oldval = sym->def[S_DEF_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->def[S_DEF_USER].val = val = malloc(size);
604		*val++ = '0';
605		*val++ = 'x';
606	} else if (!oldval || strcmp(oldval, newval))
607		sym->def[S_DEF_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	if (isconst)
683		symbol->flags |= SYMBOL_CONST;
684
685	symbol->next = symbol_hash[hash];
686	symbol_hash[hash] = symbol;
687
688	return symbol;
689}
690
691struct symbol *sym_find(const char *name)
692{
693	struct symbol *symbol = NULL;
694	const char *ptr;
695	int hash = 0;
696
697	if (!name)
698		return NULL;
699
700	if (name[0] && !name[1]) {
701		switch (name[0]) {
702		case 'y': return &symbol_yes;
703		case 'm': return &symbol_mod;
704		case 'n': return &symbol_no;
705		}
706	}
707	for (ptr = name; *ptr; ptr++)
708		hash += *ptr;
709	hash &= 0xff;
710
711	for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
712		if (!strcmp(symbol->name, name) &&
713		    !(symbol->flags & SYMBOL_CONST))
714				break;
715	}
716
717	return symbol;
718}
719
720struct symbol **sym_re_search(const char *pattern)
721{
722	struct symbol *sym, **sym_arr = NULL;
723	int i, cnt, size;
724	regex_t re;
725
726	cnt = size = 0;
727	/* Skip if empty */
728	if (strlen(pattern) == 0)
729		return NULL;
730	if (regcomp(&re, pattern, REG_EXTENDED|REG_NOSUB|REG_ICASE))
731		return NULL;
732
733	for_all_symbols(i, sym) {
734		if (sym->flags & SYMBOL_CONST || !sym->name)
735			continue;
736		if (regexec(&re, sym->name, 0, NULL, 0))
737			continue;
738		if (cnt + 1 >= size) {
739			void *tmp = sym_arr;
740			size += 16;
741			sym_arr = realloc(sym_arr, size * sizeof(struct symbol *));
742			if (!sym_arr) {
743				free(tmp);
744				return NULL;
745			}
746		}
747		sym_arr[cnt++] = sym;
748	}
749	if (sym_arr)
750		sym_arr[cnt] = NULL;
751	regfree(&re);
752
753	return sym_arr;
754}
755
756
757struct symbol *sym_check_deps(struct symbol *sym);
758
759static struct symbol *sym_check_expr_deps(struct expr *e)
760{
761	struct symbol *sym;
762
763	if (!e)
764		return NULL;
765	switch (e->type) {
766	case E_OR:
767	case E_AND:
768		sym = sym_check_expr_deps(e->left.expr);
769		if (sym)
770			return sym;
771		return sym_check_expr_deps(e->right.expr);
772	case E_NOT:
773		return sym_check_expr_deps(e->left.expr);
774	case E_EQUAL:
775	case E_UNEQUAL:
776		sym = sym_check_deps(e->left.sym);
777		if (sym)
778			return sym;
779		return sym_check_deps(e->right.sym);
780	case E_SYMBOL:
781		return sym_check_deps(e->left.sym);
782	default:
783		break;
784	}
785	printf("Oops! How to check %d?\n", e->type);
786	return NULL;
787}
788
789/* return NULL when dependencies are OK */
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		fprintf(stderr, "%s:%d:error: found recursive dependency: %s",
797		        sym->prop->file->name, sym->prop->lineno, sym->name);
798		return sym;
799	}
800	if (sym->flags & SYMBOL_CHECKED)
801		return NULL;
802
803	sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
804	sym2 = sym_check_expr_deps(sym->rev_dep.expr);
805	if (sym2)
806		goto out;
807
808	for (prop = sym->prop; prop; prop = prop->next) {
809		if (prop->type == P_CHOICE || prop->type == P_SELECT)
810			continue;
811		sym2 = sym_check_expr_deps(prop->visible.expr);
812		if (sym2)
813			goto out;
814		if (prop->type != P_DEFAULT || sym_is_choice(sym))
815			continue;
816		sym2 = sym_check_expr_deps(prop->expr);
817		if (sym2)
818			goto out;
819	}
820out:
821	if (sym2)
822		fprintf(stderr, " -> %s%s", sym->name, sym2 == sym? "\n": "");
823	sym->flags &= ~SYMBOL_CHECK;
824	return sym2;
825}
826
827struct property *prop_alloc(enum prop_type type, struct symbol *sym)
828{
829	struct property *prop;
830	struct property **propp;
831
832	prop = malloc(sizeof(*prop));
833	memset(prop, 0, sizeof(*prop));
834	prop->type = type;
835	prop->sym = sym;
836	prop->file = current_file;
837	prop->lineno = zconf_lineno();
838
839	/* append property to the prop list of symbol */
840	if (sym) {
841		for (propp = &sym->prop; *propp; propp = &(*propp)->next)
842			;
843		*propp = prop;
844	}
845
846	return prop;
847}
848
849struct symbol *prop_get_symbol(struct property *prop)
850{
851	if (prop->expr && (prop->expr->type == E_SYMBOL ||
852			   prop->expr->type == E_CHOICE))
853		return prop->expr->left.sym;
854	return NULL;
855}
856
857const char *prop_get_type_name(enum prop_type type)
858{
859	switch (type) {
860	case P_PROMPT:
861		return "prompt";
862	case P_COMMENT:
863		return "comment";
864	case P_MENU:
865		return "menu";
866	case P_DEFAULT:
867		return "default";
868	case P_CHOICE:
869		return "choice";
870	case P_SELECT:
871		return "select";
872	case P_RANGE:
873		return "range";
874	case P_UNKNOWN:
875		break;
876	}
877	return "unknown";
878}
879