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