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