xref: /inferno-os/libinterp/prefab.c (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
1 #include <lib9.h>
2 #include <kernel.h>
3 #include "interp.h"
4 #include "isa.h"
5 #include "runt.h"
6 #include "prefabmod.h"
7 #include "draw.h"
8 #include "drawif.h"
9 #include "prefab.h"
10 #include "raise.h"
11 
12 uchar elementmap[] = Prefab_Element_map;
13 uchar compoundmap[] = Prefab_Compound_map;
14 uchar layoutmap[] = Prefab_Layout_map;
15 
16 void	freeprefabcompound(Heap*, int);
17 
18 Type*	TCompound;
19 Type*	TElement;
20 Type*	TLayout;
21 
22 /* Infrared remote buttons known to Compound_select */
23 enum
24 {
25 	IRFF		= 14,
26 	IRRew		= 15,
27 	IRUp		= 16,
28 	IRDn		= 17,
29 	IRSelect	= 18,
30 	IREnter	= 20,
31 };
32 
33 void
prefabmodinit(void)34 prefabmodinit(void)
35 {
36 	TElement = dtype(freeheap, sizeof(PElement), elementmap, sizeof(elementmap));
37 	TLayout = dtype(freeheap, Prefab_Layout_size, layoutmap, sizeof(layoutmap));
38 	TCompound = dtype(freeprefabcompound, sizeof(PCompound), compoundmap, sizeof(compoundmap));
39 	builtinmod("$Prefab", Prefabmodtab, Prefabmodlen);
40 }
41 
42 PElement*
checkelement(Prefab_Element * de)43 checkelement(Prefab_Element *de)
44 {
45 	PElement *pe;
46 
47 	pe = lookupelement(de);
48 	if(pe == H)
49 		error(exType);
50 	return pe;
51 }
52 
53 PCompound*
checkcompound(Prefab_Compound * de)54 checkcompound(Prefab_Compound *de)
55 {
56 	PCompound *pe;
57 
58 	pe = lookupcompound(de);
59 	if(pe == H)
60 		error(exType);
61 	return pe;
62 }
63 
64 PElement*
lookupelement(Prefab_Element * de)65 lookupelement(Prefab_Element *de)
66 {
67 	PElement *pe;
68 	if(de == H)
69 		return H;
70 	if(D2H(de)->t != TElement)
71 		return H;
72 	pe = (PElement*)de;
73 	if(de->kind!=pe->pkind || de->kids!=pe->first)
74 		return H;
75 	return pe;
76 }
77 
78 PCompound*
lookupcompound(Prefab_Compound * dc)79 lookupcompound(Prefab_Compound *dc)
80 {
81 	if(dc == H)
82 		return H;
83 	if(D2H(dc)->t != TCompound)
84 		return H;
85 	return (PCompound*)dc;
86 }
87 
88 void
freeprefabcompound(Heap * h,int swept)89 freeprefabcompound(Heap *h, int swept)
90 {
91 	Image *i;
92 	Prefab_Compound *d;
93 	PCompound *pc;
94 
95 	d = H2D(Prefab_Compound*, h);
96 	pc = lookupcompound(d);
97 	/* disconnect compound from image refresh daemon */
98 	i = lookupimage(pc->c.image);
99 	if(i != nil)
100 		delrefresh(i);
101 	if(!swept && TCompound->np)
102 		freeptrs(d, TCompound);
103 	/* header will be freed by caller */
104 }
105 
106 static
107 PElement*
findtag(PElement * pelem,char * tag)108 findtag(PElement *pelem, char *tag)
109 {
110 	PElement *pe, *t;
111 	List *l;
112 
113 	if(pelem==H || tag[0]==0)
114 		return pelem;
115 	for(l=pelem->first; l!=H; l=l->tail){
116 		pe = *(PElement**)l->data;
117 		if(strcmp(tag, string2c(pe->e.tag)) == 0)
118 			return pe;
119 		else if(pe->pkind==EHorizontal || pe->pkind==EVertical){
120 			t = findtag(pe, tag);
121 			if(t != H)
122 				return t;
123 		}
124 	}
125 	return H;
126 }
127 
128 int
badenviron(Prefab_Environ * env,int err)129 badenviron(Prefab_Environ *env, int err)
130 {
131 	Prefab_Style *s;
132 
133 	if(env == H)
134 		goto bad;
135 	s = env->style;
136 	if(s == H)
137 		goto bad;
138 	if(s->titlefont==H || s->textfont==H)
139 		goto bad;
140 	if(s->elemcolor==H || s->edgecolor==H)
141 		goto bad;
142 	if(s->titlecolor==H || s->textcolor==H || s->highlightcolor==H)
143 		goto bad;
144 	return 0;
145 bad:
146 	if(err)
147 		error(exType);
148 	return 1;
149 }
150 
151 void
Element_iconseparator(void * fp,int kind)152 Element_iconseparator(void *fp, int kind)
153 {
154 	F_Element_icon *f;
155 	PElement *e;
156 	Image *icon;
157 	int locked;
158 
159 	f = fp;
160 	badenviron(f->env, 1);
161 	checkimage(f->mask);
162 	icon = checkimage(f->icon);
163 	locked = lockdisplay(icon->display);
164 	destroy(*f->ret);
165 	*f->ret = H;
166 	if(kind == ESeparator)
167 		e = separatorelement(f->env, f->r, f->icon, f->mask);
168 	else
169 		e = iconelement(f->env, f->r, f->icon, f->mask);
170 	*f->ret = (Prefab_Element*)e;
171 	if(locked)
172 		unlockdisplay(icon->display);
173 }
174 
175 void
Element_icon(void * fp)176 Element_icon(void *fp)
177 {
178 	Element_iconseparator(fp, EIcon);
179 }
180 
181 void
Element_separator(void * fp)182 Element_separator(void *fp)
183 {
184 	Element_iconseparator(fp, ESeparator);
185 }
186 
187 void
Element_text(void * fp)188 Element_text(void *fp)
189 {
190 	F_Element_text *f;
191 	PElement *pelem;
192 	Display *disp;
193 	int locked;
194 
195 	f = fp;
196 	badenviron(f->env, 1);
197 	if(f->kind!=EText && f->kind!=ETitle)
198 		return;
199 
200 	disp = checkscreen(f->env->screen)->display;
201 	locked = lockdisplay(disp);
202 	destroy(*f->ret);
203 	*f->ret = H;
204 	pelem = textelement(f->env, f->text, f->r, f->kind);
205 	*f->ret = (Prefab_Element*)pelem;
206 	if(locked)
207 		unlockdisplay(disp);
208 }
209 
210 void
Element_layout(void * fp)211 Element_layout(void *fp)
212 {
213 	F_Element_layout *f;
214 	PElement *pelem;
215 	Display *disp;
216 	int locked;
217 
218 	f = fp;
219 	badenviron(f->env, 1);
220 	if(f->kind!=EText && f->kind!=ETitle)
221 		return;
222 
223 	disp = checkscreen(f->env->screen)->display;
224 	locked = lockdisplay(disp);
225 	destroy(*f->ret);
226 	*f->ret = H;
227 	pelem = layoutelement(f->env, f->lay, f->r, f->kind);
228 	*f->ret = (Prefab_Element*)pelem;
229 	if(locked)
230 		unlockdisplay(disp);
231 }
232 
233 void
Element_elist(void * fp)234 Element_elist(void *fp)
235 {
236 	F_Element_elist *f;
237 	PElement *pelist;
238 	Display *disp;
239 	int locked;
240 
241 	f = fp;
242 	if(f->elem != H)
243 		checkelement(f->elem);
244 	badenviron(f->env, 1);
245 	if(f->kind!=EHorizontal && f->kind!=EVertical)
246 		return;
247 
248 	disp = checkscreen(f->env->screen)->display;
249 	locked = lockdisplay(disp);
250 	destroy(*f->ret);
251 	*f->ret = H;
252 	pelist = elistelement(f->env, f->elem, f->kind);
253 	*f->ret = (Prefab_Element*)pelist;
254 	if(locked)
255 		unlockdisplay(disp);
256 }
257 
258 void
Element_append(void * fp)259 Element_append(void *fp)
260 {
261 	F_Element_append *f;
262 
263 	f = fp;
264 	*f->ret = 0;
265 	if(f->elist==H || f->elem==H)
266 		return;
267 
268 	badenviron(f->elist->environ, 1);
269 	checkelement(f->elist);
270 	checkelement(f->elem);
271 
272 	if(f->elist->kind!=EHorizontal && f->elist->kind!=EVertical)
273 		return;
274 
275 	if(appendelist(f->elist, f->elem) != H)
276 		*f->ret = 1;
277 }
278 
279 void
Element_adjust(void * fp)280 Element_adjust(void *fp)
281 {
282 	F_Element_adjust *f;
283 	Display *disp;
284 	int locked;
285 
286 	f = fp;
287 	checkelement(f->elem);
288 	badenviron(f->elem->environ, 1);
289 	disp = checkscreen(f->elem->environ->screen)->display;
290 	locked = lockdisplay(disp);
291 	adjustelement(f->elem, f->equal, f->dir);
292 	if(locked)
293 		unlockdisplay(disp);
294 }
295 
296 void
Element_show(void * fp)297 Element_show(void *fp)
298 {
299 	F_Element_show *f;
300 	Display *disp;
301 	int locked;
302 
303 	f = fp;
304 	checkelement(f->elem);
305 	checkelement(f->elist);
306 	badenviron(f->elem->environ, 1);
307 	disp = checkscreen(f->elem->environ->screen)->display;
308 	locked = lockdisplay(disp);
309 	*f->ret = showelement(f->elist, f->elem);
310 	if(locked)
311 		unlockdisplay(disp);
312 }
313 
314 void
Element_clip(void * fp)315 Element_clip(void *fp)
316 {
317 	F_Element_clip *f;
318 	Rectangle r;
319 	Display *disp;
320 	int locked;
321 
322 	f = fp;
323 	checkelement(f->elem);
324 	badenviron(f->elem->environ, 1);
325 	R2R(r, f->r);
326 	disp = checkscreen(f->elem->environ->screen)->display;
327 	locked = lockdisplay(disp);
328 	clipelement(f->elem, r);
329 	if(locked)
330 		unlockdisplay(disp);
331 }
332 
333 void
Element_translatescroll(void * fp,int trans)334 Element_translatescroll(void *fp, int trans)
335 {
336 	F_Element_scroll *f;
337 	Point d;
338 	Display *disp;
339 	int locked, moved;
340 
341 	f = fp;
342 	checkelement(f->elem);
343 	badenviron(f->elem->environ, 1);
344 	P2P(d, f->d);
345 	disp = checkscreen(f->elem->environ->screen)->display;
346 	locked = lockdisplay(disp);
347 	if(trans)
348 		translateelement(f->elem, d);
349 	else{
350 		moved = 0;
351 		scrollelement(f->elem, d, &moved);
352 	}
353 	if(locked)
354 		unlockdisplay(disp);
355 }
356 
357 void
Element_scroll(void * fp)358 Element_scroll(void *fp)
359 {
360 	Element_translatescroll(fp, 0);
361 }
362 
363 void
Element_translate(void * fp)364 Element_translate(void *fp)
365 {
366 	Element_translatescroll(fp, 1);
367 }
368 
369 void
Compound_iconbox(void * fp)370 Compound_iconbox(void *fp)
371 {
372 	F_Compound_iconbox *f;
373 	Image *icon;
374 	int locked;
375 	PCompound *pc;
376 
377 	f = fp;
378 	badenviron(f->env, 1);
379 	checkimage(f->mask);
380 	icon = checkimage(f->icon);
381 	locked = lockdisplay(icon->display);
382 	destroy(*f->ret);
383 	*f->ret = H;
384 	pc = iconbox(f->env, f->p, f->title, f->icon, f->mask);
385 	*f->ret = &pc->c;
386 	if(locked)
387 		unlockdisplay(icon->display);
388 }
389 
390 void
Compound_textbox(void * fp)391 Compound_textbox(void *fp)
392 {
393 	F_Compound_textbox *f;
394 	Display *disp;
395 	int locked;
396 	PCompound *pc;
397 
398 	f = fp;
399 	badenviron(f->env, 1);
400 	disp = checkscreen(f->env->screen)->display;
401 	locked = lockdisplay(disp);
402 	destroy(*f->ret);
403 	*f->ret = H;
404 	pc = textbox(f->env, f->r, f->title, f->text);
405 	*f->ret = &pc->c;
406 	if(locked)
407 		unlockdisplay(disp);
408 }
409 
410 void
Compound_layoutbox(void * fp)411 Compound_layoutbox(void *fp)
412 {
413 	F_Compound_layoutbox *f;
414 	Display *disp;
415 	int locked;
416 	PCompound *pc;
417 
418 	f = fp;
419 	badenviron(f->env, 1);
420 	disp = checkscreen(f->env->screen)->display;
421 	locked = lockdisplay(disp);
422 	destroy(*f->ret);
423 	*f->ret = H;
424 	pc = layoutbox(f->env, f->r, f->title, f->lay);
425 	*f->ret = &pc->c;
426 	if(locked)
427 		unlockdisplay(disp);
428 }
429 
430 void
Compound_box(void * fp)431 Compound_box(void *fp)
432 {
433 	F_Compound_box *f;
434 	Display *disp;
435 	int locked;
436 	PCompound *pc;
437 
438 	f = fp;
439 	badenviron(f->env, 1);
440 	if(f->title != H)
441 		checkelement(f->title);
442 	checkelement(f->elist);
443 	disp = checkscreen(f->env->screen)->display;
444 	locked = lockdisplay(disp);
445 	destroy(*f->ret);
446 	*f->ret = H;
447 	pc = box(f->env, f->p, f->title, f->elist);
448 	*f->ret = &pc->c;
449 	if(locked)
450 		unlockdisplay(disp);
451 }
452 
453 void
Compound_draw(void * fp)454 Compound_draw(void *fp)
455 {
456 	F_Compound_draw *f;
457 	PCompound *pc;
458 	int locked;
459 
460 	f = fp;
461 	if(f->comp == H)
462 		return;
463 	pc = checkcompound(f->comp);
464 	badenviron(pc->c.environ, 1);
465 	locked = lockdisplay(pc->display);
466 	drawcompound(&pc->c);
467 	flushimage(pc->display, 1);
468 	if(locked)
469 		unlockdisplay(pc->display);
470 }
471 
472 void
Compound_redraw(void * fp)473 Compound_redraw(void *fp)
474 {
475 	F_Compound_redraw *f;
476 	PCompound *pc;
477 	Image *i;
478 	int locked;
479 
480 	f = fp;
481 	if(f->comp == H)
482 		return;
483 	pc = checkcompound(f->comp);
484 	badenviron(pc->c.environ, 1);
485 	i = checkimage(pc->c.image);
486 	locked = lockdisplay(pc->display);
487 	redrawcompound(i, IRECT(f->r), &pc->c);
488 	flushimage(pc->display, 1);
489 	if(locked)
490 		unlockdisplay(pc->display);
491 }
492 
493 static
494 PElement*
pelement(Prefab_Compound * comp,Prefab_Element * elem)495 pelement(Prefab_Compound *comp, Prefab_Element *elem)
496 {
497 	PElement *pe;
498 
499 	if(comp == H)
500 		return H;
501 	checkcompound(comp);
502 	badenviron(comp->environ, 1);
503 	pe = lookupelement(elem);
504 	return pe;
505 }
506 
507 void
Compound_highlight(void * fp)508 Compound_highlight(void *fp)
509 {
510 	F_Compound_highlight *f;
511 	PCompound *pc;
512 	PElement *pe;
513 	Image *i;
514 	int locked;
515 
516 	f = fp;
517 	pe = pelement(f->comp, f->elem);
518 	if(pe == H)
519 		return;
520 	pc = (PCompound*)f->comp;
521 	i = checkimage(pc->c.image);
522 	locked = lockdisplay(pc->display);
523 	highlightelement(&pe->e, i, &pc->c, f->on);
524 	flushimage(pc->display, 1);
525 	if(locked)
526 		unlockdisplay(pc->display);
527 }
528 
529 void
Compound_scroll(void * fp)530 Compound_scroll(void *fp)
531 {
532 	F_Compound_scroll *f;
533 	PCompound *pc;
534 	PElement *pe;
535 	int locked;
536 	Image *i;
537 	int moved;
538 
539 	f = fp;
540 	pe = pelement(f->comp, f->elem);
541 	if(pe == H)
542 		return;
543 	pc = (PCompound*)f->comp;
544 	i = checkimage(pc->c.image);
545 	locked = lockdisplay(pc->display);
546 	moved = 0;
547 	scrollelement(&pe->e, IPOINT(f->d), &moved);
548 	if(moved){
549 		drawelement(&pe->e, i, IRECT(pe->e.r), 0, 0);
550 		flushimage(pc->display, 1);
551 	}
552 	if(locked)
553 		unlockdisplay(pc->display);
554 }
555 
556 void
Compound_show(void * fp)557 Compound_show(void *fp)
558 {
559 	F_Compound_show *f;
560 	PCompound *pc;
561 	PElement *pe;
562 	int locked;
563 
564 	f = fp;
565 	pe = pelement(f->comp, f->elem);
566 	if(pe == H)
567 		return;
568 	pc = (PCompound*)f->comp;
569 	locked = lockdisplay(pc->display);
570 	*f->ret = showelement(pc->c.contents, &pe->e);
571 	flushimage(pc->display, 1);
572 	if(locked)
573 		unlockdisplay(pc->display);
574 }
575 
576 static
577 PElement*
element(PElement * plist,int index,int * ip)578 element(PElement *plist, int index, int *ip)
579 {
580 	int i;
581 	PElement *pe;
582 	List *l;
583 
584 	i = 0;
585 	pe = H;
586 	for(l=plist->first; l!=H; l=l->tail){
587 		pe = *(PElement**)l->data;
588 		if(pe->pkind == ESeparator)
589 			continue;
590 		if(i == index)
591 			break;
592 		i++;
593 	}
594 	if(ip)
595 		*ip = i;
596 	if(l == H)
597 		return H;
598 	return pe;
599 }
600 
601 static
602 int
wrapelement(PElement * plist,int index,int ntag)603 wrapelement(PElement *plist, int index, int ntag)
604 {
605 	int i, wrap;
606 
607 	if(ntag > 0){
608 		if(index < 0)
609 			return ntag-1;
610 		if(index >= ntag)
611 			return 0;
612 		return index;
613 	}
614 	wrap = 1;
615 	if(index < 0){
616 		index = 1000000;	/* will seek to end */
617 		wrap = 0;
618 	}
619 	if(element(plist, index, &i)==H && index!=0){
620 		if(wrap)	/* went off end; wrap to beginning */
621 			return wrapelement(plist, 0, 0);
622 		if(i > 0)
623 			--i;
624 	}
625 	return i;
626 }
627 
628 void
dohighlight(PCompound * pc,PElement * list,PElement * pe,int on)629 dohighlight(PCompound *pc, PElement *list, PElement *pe, int on)
630 {
631 	Image *i;
632 
633 	/* see if we need to scroll */
634 	i = lookupimage(pc->c.image);
635 	if(i == nil)
636 		return;
637 	if(on && showelement(&list->e, &pe->e))
638 		redrawcompound(i, IRECT(pc->c.contents->r), &pc->c);
639 	highlightelement(&pe->e, i, &pc->c, on);
640 }
641 
642 void
highlight(PCompound * pc,PElement * list,int index,int on)643 highlight(PCompound *pc, PElement *list, int index, int on)
644 {
645 	dohighlight(pc, list, element(list, index, nil), on);
646 }
647 
648 static
649 PElement**
tags(PElement * pelem,int * ntag)650 tags(PElement *pelem, int *ntag)
651 {
652 	int n, nalloc, nn;
653 	List *l;
654 	PElement *pe, **tagged, **ntagged;
655 
656 	n = 0;
657 	nalloc = 0;
658 	tagged = nil;
659 	*ntag = 0;
660 	for(l=pelem->first; l!=H; l=l->tail){
661 		pe = *(PElement**)l->data;
662 		if(pe->e.tag != H){
663 			if(nalloc == n){
664 				nalloc += 10;
665 				tagged = realloc(tagged, nalloc*sizeof(PElement*));
666 				if(tagged == nil)
667 					return nil;
668 			}
669 			tagged[n++] = pe;
670 		}else if(pe->pkind==EHorizontal || pe->pkind==EVertical){
671 			ntagged = tags(pe, &nn);
672 			if(nn > 0){
673 				if(nalloc < n+nn){
674 					nalloc = n+nn+10;
675 					tagged = realloc(tagged, nalloc*sizeof(PElement*));
676 					if(tagged == nil){
677 						free(ntagged);
678 						return nil;
679 					}
680 				}
681 				memmove(tagged+n, ntagged, nn*sizeof(PElement*));
682 				free(ntagged);
683 				n += nn;
684 			}
685 		}
686 	}
687 	*ntag = n;
688 	return tagged;
689 }
690 
691 void
doselect(void * fp,int dotags)692 doselect(void *fp, int dotags)
693 {
694 	F_Compound_select *f;
695 	PCompound *pc;
696 	PElement *pe;
697 	WORD *val;
698 	List *l;
699 	Prefab_Element *t;
700 	int i, lasti, ntag;
701 	PElement **tagged;
702 	int locked;
703 
704 	f = fp;
705 	pc = checkcompound(f->comp);
706 	pe = lookupelement(f->elem);
707 	if(pe->pkind!=EHorizontal && pe->pkind!=EVertical || pe->nkids == 0){
708     Bad:
709 		destroy(f->ret->t2);
710 		f->ret->t0 = 9999;
711 		f->ret->t1 = 0;
712 		f->ret->t2 = H;
713 		return;
714 	}
715 	ntag = 0;
716 	tagged = 0;
717 	/* check at least one selectable item */
718 	if(dotags){
719 		tagged = tags(pe, &ntag);
720 		if(ntag > 0)
721 			goto OK;
722 	}else
723 		for(l=pe->first; l!=H; l=l->tail){
724 			t = *(Prefab_Element**)l->data;
725 			if(t->kind != ESeparator)
726 				goto OK;
727 		}
728 	goto Bad;
729 
730     OK:
731 	i = f->i;
732 	i = wrapelement(pe, i, ntag);
733 	lasti = i;
734 	locked = lockdisplay(pc->display);
735 	if(dotags)
736 		dohighlight(pc, pe, tagged[i], 1);
737 	else
738 		highlight(pc, pe, i, 1);
739 	/* val must be in shared memory, but stacks not shared */
740 	val = malloc(sizeof(WORD));
741 	if(val == nil)
742 		goto Bad;
743 	for(;;){
744 		if(lasti != i){
745 			if(dotags){
746 				dohighlight(pc, pe, tagged[lasti], 0);
747 				dohighlight(pc, pe, tagged[i], 1);
748 			}else{
749 				highlight(pc, pe, lasti, 0);
750 				highlight(pc, pe, i, 1);
751 			}
752 			lasti = i;
753 		}
754 		flushimage(pc->display, 1);
755 		if(locked)
756 			unlockdisplay(pc->display);
757 		crecv(f->c, val);
758 		locked = lockdisplay(pc->display);
759 		switch(*val){
760 		case IRUp:
761 			if(pe->pkind != EVertical)
762 				goto Default;
763 			goto Up;
764 		case IRRew:
765 			if(pe->pkind != EHorizontal)
766 				goto Default;
767 		Up:
768 			i = wrapelement(pe, i-1, ntag);
769 			break;
770 		case IRSelect:
771 			if(dotags)
772 				dohighlight(pc, pe, tagged[i], 0);
773 			else
774 				highlight(pc, pe, i, 0);
775 			f->ret->t0 = *val;
776 			f->ret->t1 = i;
777     Return:
778 			flushimage(pc->display, 1);
779 			if(dotags)
780 				pe = tagged[i];
781 			else
782 				pe = element(pe, i, nil);
783 			destroy(f->ret->t2);
784 			D2H(pe)->ref++;
785 			f->ret->t2 = &pe->e;
786 			if(locked)
787 				unlockdisplay(pc->display);
788 			free(val);
789 			free(tagged);
790 			return;
791 		case IRDn:
792 			if(pe->pkind != EVertical)
793 				goto Default;
794 			goto Down;
795 		case IRFF:
796 			if(pe->pkind != EHorizontal)
797 				goto Default;
798 		Down:
799 			i = wrapelement(pe, i+1, ntag);
800 			break;
801 		default:
802     Default:
803 			if(dotags)
804 				dohighlight(pc, pe, tagged[lasti], 0);
805 			else
806 				highlight(pc, pe, lasti, 0);
807 			f->ret->t0 = *val;
808 			f->ret->t1 = i;
809 			goto Return;
810 		}
811 	}
812 }
813 
814 void
Compound_tagselect(void * fp)815 Compound_tagselect(void *fp)
816 {
817 	doselect(fp, 1);
818 }
819 
820 void
Compound_select(void * fp)821 Compound_select(void *fp)
822 {
823 	doselect(fp, 0);
824 }
825