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	sym = sym_lookup("ARCH", 0);
59	sym->type = S_STRING;
60	sym->flags |= SYMBOL_AUTO;
61	p = getenv("ARCH");
62	if (p)
63		sym_add_default(sym, p);
64
65	sym = sym_lookup("KERNELVERSION", 0);
66	sym->type = S_STRING;
67	sym->flags |= SYMBOL_AUTO;
68	p = getenv("KERNELVERSION");
69	if (p)
70		sym_add_default(sym, p);
71
72	sym = sym_lookup("UNAME_RELEASE", 0);
73	sym->type = S_STRING;
74	sym->flags |= SYMBOL_AUTO;
75	sym_add_default(sym, uts.release);
76}
77
78enum symbol_type sym_get_type(struct symbol *sym)
79{
80	enum symbol_type type = sym->type;
81
82	if (type == S_TRISTATE) {
83		if (sym_is_choice_value(sym) && sym->visible == yes)
84			type = S_BOOLEAN;
85		else if (modules_val == no)
86			type = S_BOOLEAN;
87	}
88	return type;
89}
90
91const char *sym_type_name(enum symbol_type type)
92{
93	switch (type) {
94	case S_BOOLEAN:
95		return "boolean";
96	case S_TRISTATE:
97		return "tristate";
98	case S_INT:
99		return "integer";
100	case S_HEX:
101		return "hex";
102	case S_STRING:
103		return "string";
104	case S_UNKNOWN:
105		return "unknown";
106	case S_OTHER:
107		break;
108	}
109	return "???";
110}
111
112struct property *sym_get_choice_prop(struct symbol *sym)
113{
114	struct property *prop;
115
116	for_all_choices(sym, prop)
117		return prop;
118	return NULL;
119}
120
121struct property *sym_get_default_prop(struct symbol *sym)
122{
123	struct property *prop;
124
125	for_all_defaults(sym, prop) {
126		prop->visible.tri = expr_calc_value(prop->visible.expr);
127		if (prop->visible.tri != no)
128			return prop;
129	}
130	return NULL;
131}
132
133struct property *sym_get_range_prop(struct symbol *sym)
134{
135	struct property *prop;
136
137	for_all_properties(sym, prop, P_RANGE) {
138		prop->visible.tri = expr_calc_value(prop->visible.expr);
139		if (prop->visible.tri != no)
140			return prop;
141	}
142	return NULL;
143}
144
145static int sym_get_range_val(struct symbol *sym, int base)
146{
147	sym_calc_value(sym);
148	switch (sym->type) {
149	case S_INT:
150		base = 10;
151		break;
152	case S_HEX:
153		base = 16;
154		break;
155	default:
156		break;
157	}
158	return strtol(sym->curr.val, NULL, base);
159}
160
161static void sym_validate_range(struct symbol *sym)
162{
163	struct property *prop;
164	int base, val, val2;
165	char str[64];
166
167	switch (sym->type) {
168	case S_INT:
169		base = 10;
170		break;
171	case S_HEX:
172		base = 16;
173		break;
174	default:
175		return;
176	}
177	prop = sym_get_range_prop(sym);
178	if (!prop)
179		return;
180	val = strtol(sym->curr.val, NULL, base);
181	val2 = sym_get_range_val(prop->expr->left.sym, base);
182	if (val >= val2) {
183		val2 = sym_get_range_val(prop->expr->right.sym, base);
184		if (val <= val2)
185			return;
186	}
187	if (sym->type == S_INT)
188		sprintf(str, "%d", val2);
189	else
190		sprintf(str, "0x%x", val2);
191	sym->curr.val = strdup(str);
192}
193
194static void sym_calc_visibility(struct symbol *sym)
195{
196	struct property *prop;
197	tristate tri;
198
199	/* any prompt visible? */
200	tri = no;
201	for_all_prompts(sym, prop) {
202		prop->visible.tri = expr_calc_value(prop->visible.expr);
203		tri = E_OR(tri, prop->visible.tri);
204	}
205	if (tri == mod && (sym->type != S_TRISTATE || modules_val == no))
206		tri = yes;
207	if (sym->visible != tri) {
208		sym->visible = tri;
209		sym_set_changed(sym);
210	}
211	if (sym_is_choice_value(sym))
212		return;
213	tri = no;
214	if (sym->rev_dep.expr)
215		tri = expr_calc_value(sym->rev_dep.expr);
216	if (tri == mod && sym_get_type(sym) == S_BOOLEAN)
217		tri = yes;
218	if (sym->rev_dep.tri != tri) {
219		sym->rev_dep.tri = tri;
220		sym_set_changed(sym);
221	}
222}
223
224static struct symbol *sym_calc_choice(struct symbol *sym)
225{
226	struct symbol *def_sym;
227	struct property *prop;
228	struct expr *e;
229
230	/* is the user choice visible? */
231	def_sym = sym->def[S_DEF_USER].val;
232	if (def_sym) {
233		sym_calc_visibility(def_sym);
234		if (def_sym->visible != no)
235			return def_sym;
236	}
237
238	/* any of the defaults visible? */
239	for_all_defaults(sym, prop) {
240		prop->visible.tri = expr_calc_value(prop->visible.expr);
241		if (prop->visible.tri == no)
242			continue;
243		def_sym = prop_get_symbol(prop);
244		sym_calc_visibility(def_sym);
245		if (def_sym->visible != no)
246			return def_sym;
247	}
248
249	/* just get the first visible value */
250	prop = sym_get_choice_prop(sym);
251	for (e = prop->expr; e; e = e->left.expr) {
252		def_sym = e->right.sym;
253		sym_calc_visibility(def_sym);
254		if (def_sym->visible != no)
255			return def_sym;
256	}
257
258	/* no choice? reset tristate value */
259	sym->curr.tri = no;
260	return NULL;
261}
262
263void sym_calc_value(struct symbol *sym)
264{
265	struct symbol_value newval, oldval;
266	struct property *prop;
267	struct expr *e;
268
269	if (!sym)
270		return;
271
272	if (sym->flags & SYMBOL_VALID)
273		return;
274	sym->flags |= SYMBOL_VALID;
275
276	oldval = sym->curr;
277
278	switch (sym->type) {
279	case S_INT:
280	case S_HEX:
281	case S_STRING:
282		newval = symbol_empty.curr;
283		break;
284	case S_BOOLEAN:
285	case S_TRISTATE:
286		newval = symbol_no.curr;
287		break;
288	default:
289		sym->curr.val = sym->name;
290		sym->curr.tri = no;
291		return;
292	}
293	if (!sym_is_choice_value(sym))
294		sym->flags &= ~SYMBOL_WRITE;
295
296	sym_calc_visibility(sym);
297
298	/* set default if recursively called */
299	sym->curr = newval;
300
301	switch (sym_get_type(sym)) {
302	case S_BOOLEAN:
303	case S_TRISTATE:
304		if (sym_is_choice_value(sym) && sym->visible == yes) {
305			prop = sym_get_choice_prop(sym);
306			newval.tri = (prop_get_symbol(prop)->curr.val == sym) ? yes : no;
307		} else if (E_OR(sym->visible, sym->rev_dep.tri) != no) {
308			sym->flags |= SYMBOL_WRITE;
309			if (sym_has_value(sym))
310				newval.tri = sym->def[S_DEF_USER].tri;
311			else if (!sym_is_choice(sym)) {
312				prop = sym_get_default_prop(sym);
313				if (prop)
314					newval.tri = expr_calc_value(prop->expr);
315			}
316			newval.tri = E_OR(E_AND(newval.tri, sym->visible), sym->rev_dep.tri);
317		} else if (!sym_is_choice(sym)) {
318			prop = sym_get_default_prop(sym);
319			if (prop) {
320				sym->flags |= SYMBOL_WRITE;
321				newval.tri = expr_calc_value(prop->expr);
322			}
323		}
324		if (newval.tri == mod && sym_get_type(sym) == S_BOOLEAN)
325			newval.tri = yes;
326		break;
327	case S_STRING:
328	case S_HEX:
329	case S_INT:
330		if (sym->visible != no) {
331			sym->flags |= SYMBOL_WRITE;
332			if (sym_has_value(sym)) {
333				newval.val = sym->def[S_DEF_USER].val;
334				break;
335			}
336		}
337		prop = sym_get_default_prop(sym);
338		if (prop) {
339			struct symbol *ds = prop_get_symbol(prop);
340			if (ds) {
341				sym->flags |= SYMBOL_WRITE;
342				sym_calc_value(ds);
343				newval.val = ds->curr.val;
344			}
345		}
346		break;
347	default:
348		;
349	}
350
351	sym->curr = newval;
352	if (sym_is_choice(sym) && newval.tri == yes)
353		sym->curr.val = sym_calc_choice(sym);
354	sym_validate_range(sym);
355
356	if (memcmp(&oldval, &sym->curr, sizeof(oldval))) {
357		sym_set_changed(sym);
358		if (modules_sym == sym) {
359			sym_set_all_changed();
360			modules_val = modules_sym->curr.tri;
361		}
362	}
363
364	if (sym_is_choice(sym)) {
365		int flags = sym->flags & (SYMBOL_CHANGED | SYMBOL_WRITE);
366		prop = sym_get_choice_prop(sym);
367		for (e = prop->expr; e; e = e->left.expr) {
368			e->right.sym->flags |= flags;
369			if (flags & SYMBOL_CHANGED)
370				sym_set_changed(e->right.sym);
371		}
372	}
373}
374
375void sym_clear_all_valid(void)
376{
377	struct symbol *sym;
378	int i;
379
380	for_all_symbols(i, sym)
381		sym->flags &= ~SYMBOL_VALID;
382	sym_change_count++;
383	if (modules_sym)
384		sym_calc_value(modules_sym);
385}
386
387void sym_set_changed(struct symbol *sym)
388{
389	struct property *prop;
390
391	sym->flags |= SYMBOL_CHANGED;
392	for (prop = sym->prop; prop; prop = prop->next) {
393		if (prop->menu)
394			prop->menu->flags |= MENU_CHANGED;
395	}
396}
397
398void sym_set_all_changed(void)
399{
400	struct symbol *sym;
401	int i;
402
403	for_all_symbols(i, sym)
404		sym_set_changed(sym);
405}
406
407bool sym_tristate_within_range(struct symbol *sym, tristate val)
408{
409	int type = sym_get_type(sym);
410
411	if (sym->visible == no)
412		return false;
413
414	if (type != S_BOOLEAN && type != S_TRISTATE)
415		return false;
416
417	if (type == S_BOOLEAN && val == mod)
418		return false;
419	if (sym->visible <= sym->rev_dep.tri)
420		return false;
421	if (sym_is_choice_value(sym) && sym->visible == yes)
422		return val == yes;
423	return val >= sym->rev_dep.tri && val <= sym->visible;
424}
425
426bool sym_set_tristate_value(struct symbol *sym, tristate val)
427{
428	tristate oldval = sym_get_tristate_value(sym);
429
430	if (oldval != val && !sym_tristate_within_range(sym, val))
431		return false;
432
433	if (!(sym->flags & SYMBOL_DEF_USER)) {
434		sym->flags |= SYMBOL_DEF_USER;
435		sym_set_changed(sym);
436	}
437	/*
438	 * setting a choice value also resets the new flag of the choice
439	 * symbol and all other choice values.
440	 */
441	if (sym_is_choice_value(sym) && val == yes) {
442		struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
443		struct property *prop;
444		struct expr *e;
445
446		cs->def[S_DEF_USER].val = sym;
447		cs->flags |= SYMBOL_DEF_USER;
448		prop = sym_get_choice_prop(cs);
449		for (e = prop->expr; e; e = e->left.expr) {
450			if (e->right.sym->visible != no)
451				e->right.sym->flags |= SYMBOL_DEF_USER;
452		}
453	}
454
455	sym->def[S_DEF_USER].tri = val;
456	if (oldval != val)
457		sym_clear_all_valid();
458
459	return true;
460}
461
462tristate sym_toggle_tristate_value(struct symbol *sym)
463{
464	tristate oldval, newval;
465
466	oldval = newval = sym_get_tristate_value(sym);
467	do {
468		switch (newval) {
469		case no:
470			newval = mod;
471			break;
472		case mod:
473			newval = yes;
474			break;
475		case yes:
476			newval = no;
477			break;
478		}
479		if (sym_set_tristate_value(sym, newval))
480			break;
481	} while (oldval != newval);
482	return newval;
483}
484
485bool sym_string_valid(struct symbol *sym, const char *str)
486{
487	signed char ch;
488
489	switch (sym->type) {
490	case S_STRING:
491		return true;
492	case S_INT:
493		ch = *str++;
494		if (ch == '-')
495			ch = *str++;
496		if (!isdigit(ch))
497			return false;
498		if (ch == '0' && *str != 0)
499			return false;
500		while ((ch = *str++)) {
501			if (!isdigit(ch))
502				return false;
503		}
504		return true;
505	case S_HEX:
506		if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))
507			str += 2;
508		ch = *str++;
509		do {
510			if (!isxdigit(ch))
511				return false;
512		} while ((ch = *str++));
513		return true;
514	case S_BOOLEAN:
515	case S_TRISTATE:
516		switch (str[0]) {
517		case 'y': case 'Y':
518		case 'm': case 'M':
519		case 'n': case 'N':
520			return true;
521		}
522		return false;
523	default:
524		return false;
525	}
526}
527
528bool sym_string_within_range(struct symbol *sym, const char *str)
529{
530	struct property *prop;
531	int val;
532
533	switch (sym->type) {
534	case S_STRING:
535		return sym_string_valid(sym, str);
536	case S_INT:
537		if (!sym_string_valid(sym, str))
538			return false;
539		prop = sym_get_range_prop(sym);
540		if (!prop)
541			return true;
542		val = strtol(str, NULL, 10);
543		return val >= sym_get_range_val(prop->expr->left.sym, 10) &&
544		       val <= sym_get_range_val(prop->expr->right.sym, 10);
545	case S_HEX:
546		if (!sym_string_valid(sym, str))
547			return false;
548		prop = sym_get_range_prop(sym);
549		if (!prop)
550			return true;
551		val = strtol(str, NULL, 16);
552		return val >= sym_get_range_val(prop->expr->left.sym, 16) &&
553		       val <= sym_get_range_val(prop->expr->right.sym, 16);
554	case S_BOOLEAN:
555	case S_TRISTATE:
556		switch (str[0]) {
557		case 'y': case 'Y':
558			return sym_tristate_within_range(sym, yes);
559		case 'm': case 'M':
560			return sym_tristate_within_range(sym, mod);
561		case 'n': case 'N':
562			return sym_tristate_within_range(sym, no);
563		}
564		return false;
565	default:
566		return false;
567	}
568}
569
570bool sym_set_string_value(struct symbol *sym, const char *newval)
571{
572	const char *oldval;
573	char *val;
574	int size;
575
576	switch (sym->type) {
577	case S_BOOLEAN:
578	case S_TRISTATE:
579		switch (newval[0]) {
580		case 'y': case 'Y':
581			return sym_set_tristate_value(sym, yes);
582		case 'm': case 'M':
583			return sym_set_tristate_value(sym, mod);
584		case 'n': case 'N':
585			return sym_set_tristate_value(sym, no);
586		}
587		return false;
588	default:
589		;
590	}
591
592	if (!sym_string_within_range(sym, newval))
593		return false;
594
595	if (!(sym->flags & SYMBOL_DEF_USER)) {
596		sym->flags |= SYMBOL_DEF_USER;
597		sym_set_changed(sym);
598	}
599
600	oldval = sym->def[S_DEF_USER].val;
601	size = strlen(newval) + 1;
602	if (sym->type == S_HEX && (newval[0] != '0' || (newval[1] != 'x' && newval[1] != 'X'))) {
603		size += 2;
604		sym->def[S_DEF_USER].val = val = malloc(size);
605		*val++ = '0';
606		*val++ = 'x';
607	} else if (!oldval || strcmp(oldval, newval))
608		sym->def[S_DEF_USER].val = val = malloc(size);
609	else
610		return true;
611
612	strcpy(val, newval);
613	free((void *)oldval);
614	sym_clear_all_valid();
615
616	return true;
617}
618
619const char *sym_get_string_value(struct symbol *sym)
620{
621	tristate val;
622
623	switch (sym->type) {
624	case S_BOOLEAN:
625	case S_TRISTATE:
626		val = sym_get_tristate_value(sym);
627		switch (val) {
628		case no:
629			return "n";
630		case mod:
631			return "m";
632		case yes:
633			return "y";
634		}
635		break;
636	default:
637		;
638	}
639	return (const char *)sym->curr.val;
640}
641
642bool sym_is_changable(struct symbol *sym)
643{
644	return sym->visible > sym->rev_dep.tri;
645}
646
647struct symbol *sym_lookup(const char *name, int isconst)
648{
649	struct symbol *symbol;
650	const char *ptr;
651	char *new_name;
652	int hash = 0;
653
654	if (name) {
655		if (name[0] && !name[1]) {
656			switch (name[0]) {
657			case 'y': return &symbol_yes;
658			case 'm': return &symbol_mod;
659			case 'n': return &symbol_no;
660			}
661		}
662		for (ptr = name; *ptr; ptr++)
663			hash += *ptr;
664		hash &= 0xff;
665
666		for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
667			if (!strcmp(symbol->name, name)) {
668				if ((isconst && symbol->flags & SYMBOL_CONST) ||
669				    (!isconst && !(symbol->flags & SYMBOL_CONST)))
670					return symbol;
671			}
672		}
673		new_name = strdup(name);
674	} else {
675		new_name = NULL;
676		hash = 256;
677	}
678
679	symbol = malloc(sizeof(*symbol));
680	memset(symbol, 0, sizeof(*symbol));
681	symbol->name = new_name;
682	symbol->type = S_UNKNOWN;
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