Fix exec from setuid/setgid binaries
[dragonfly.git] / gnu / lib / libdialog / ui_objects.c
blobdde151344a72952bd0a0c0700b29e37035371c53
1 /*
2 * Program: objects.c
3 * Author: Marc van Kempen
4 * Desc: Implementation of UI-objects:
5 * - String input fields
6 * - List selection
7 * - Buttons
9 * Copyright (c) 1995, Marc van Kempen
11 * All rights reserved.
13 * This software may be used, modified, copied, distributed, and
14 * sold, in both source and binary form provided that the above
15 * copyright and these terms are retained, verbatim, as the first
16 * lines of this file. Under no circumstances is the author
17 * responsible for the proper functioning of this software, nor does
18 * the author assume any responsibility for damages incurred with
19 * its use.
23 #include <stdlib.h>
24 #include <sys/param.h>
25 #include <ncurses.h>
26 #include <dialog.h>
27 #include "dialog.priv.h"
28 #include "ui_objects.h"
30 #define ESC 27
32 /***********************************************************************
34 * Obj routines
36 ***********************************************************************/
38 void
39 AddObj(ComposeObj **Obj, int objtype, void *obj)
41 * Desc: Add the object <obj> to the list of objects <Obj>
44 if (*Obj == NULL) {
45 /* Create the root object */
46 *Obj = (ComposeObj *) malloc( sizeof(ComposeObj) );
47 if (!Obj) {
48 printf("AddObj: Error malloc'ing ComposeObj\n");
49 exit(-1);
51 (*Obj)->objtype = objtype;
52 (*Obj)->obj = obj;
53 (*Obj)->next = NULL;
54 (*Obj)->prev = NULL;
55 } else {
56 ComposeObj *o = *Obj;
58 /* create the next object */
59 while (o->next) o = (ComposeObj *) o->next;
60 o->next = (struct ComposeObj *) malloc( sizeof(ComposeObj) );
61 if (!o->next) {
62 printf("AddObj: Error malloc'ing o->next\n");
63 exit(-1);
65 o->next->objtype = objtype;
66 o->next->obj = obj;
67 o->next->next = NULL;
68 o->next->prev = o;
71 return;
72 } /* AddObj() */
74 void
75 FreeObj(ComposeObj *Obj)
77 * Desc: free the memory occupied by *Obj
80 ComposeObj *o = Obj;
82 o = Obj;
83 while (o) {
84 o = Obj->next;
85 free(Obj);
86 Obj = o;
89 return;
90 } /* FreeObj() */
93 int
94 ReadObj(ComposeObj *Obj)
96 * Desc: navigate through the different objects calling their
97 * respective navigation routines as necessary
98 * Pre: Obj != NULL
101 ComposeObj *o;
102 ComposeObj *last; /* the last object in the list */
103 int ret; /* the return value from the selection routine */
105 /* find the last object in the list */
106 last = Obj;
107 while (last->next) last = last->next;
109 ret = 0;
110 o = Obj;
111 while ((ret != SEL_BUTTON) && (ret != SEL_ESC)) {
112 switch(o->objtype) {
113 case STRINGOBJ:
114 ret = SelectStringObj((StringObj *) o->obj);
115 break;
116 case LISTOBJ:
117 ret = SelectListObj((ListObj *) o->obj);
118 break;
119 case BUTTONOBJ:
120 ret = SelectButtonObj((ButtonObj *) o->obj);
121 break;
123 switch(ret) {
124 case KEY_DOWN:
125 case SEL_CR:
126 case SEL_TAB: /* move to the next object in the list */
127 if (o->next != NULL) {
128 o = o->next; /* next object */
129 } else {
130 o = Obj; /* beginning of the list */
132 break;
134 case KEY_UP:
135 case SEL_BACKTAB: /* move to the previous object in the list */
136 if (o->prev != NULL) {
137 o = o->prev; /* previous object */
138 } else {
139 o = last; /* end of the list */
141 break;
143 case KEY_F(1): /* display help_file */
144 case '?':
145 display_helpfile();
146 break;
150 return(ret);
152 } /* ReadObj() */
156 PollObj(ComposeObj **Obj)
158 ComposeObj *last; /* the last object in the list */
159 ComposeObj *first; /* the first object in the list */
160 int ret; /* the return value from the selection routine */
162 /* find the last object in the list */
163 last = *Obj;
164 while (last->next) last = last->next;
166 /* find the first object in the list */
167 first = *Obj;
168 while (first->prev) first = first->prev;
170 ret = 0;
171 switch((*Obj)->objtype) {
172 case STRINGOBJ:
173 ret = SelectStringObj((StringObj *) (*Obj)->obj);
174 break;
175 case LISTOBJ:
176 ret = SelectListObj((ListObj *) (*Obj)->obj);
177 break;
178 case BUTTONOBJ:
179 ret = SelectButtonObj((ButtonObj *) (*Obj)->obj);
180 break;
182 switch(ret) {
183 case KEY_DOWN:
184 case SEL_CR:
185 case SEL_TAB: /* move to the next object in the list */
186 if ((*Obj)->next != NULL) {
187 *Obj = (*Obj)->next; /* next object */
188 } else {
189 *Obj = first; /* beginning of the list */
191 break;
193 case KEY_UP:
194 case SEL_BACKTAB: /* move to the previous object in the list */
195 if ((*Obj)->prev != NULL) {
196 *Obj = (*Obj)->prev; /* previous object */
197 } else {
198 *Obj = last; /* end of the list */
200 break;
203 return(ret);
205 } /* PollObj() */
208 void
209 DelObj(ComposeObj *Obj)
211 * Desc: Free all objects
214 ComposeObj *o;
216 o = Obj;
217 while (Obj != NULL) {
218 switch(Obj->objtype) {
219 case STRINGOBJ:
220 DelStringObj((StringObj *) Obj->obj);
221 break;
222 case LISTOBJ:
223 DelListObj((ListObj *) Obj->obj);
224 break;
225 case BUTTONOBJ:
226 DelButtonObj((ButtonObj *) Obj->obj);
227 break;
229 Obj = Obj->next;
232 FreeObj(o);
233 } /* DelObj() */
235 /***********************************************************************
237 * StringObj routines
239 ***********************************************************************/
241 static void
242 outstr(WINDOW *win, char *str, int attrs)
244 if (attrs & DITEM_NO_ECHO) {
245 char *cpy;
246 int n = strlen(str);
248 cpy = alloca(n + 1);
249 memset(cpy, '*', n);
250 cpy[n] = '\0';
251 waddstr(win, cpy);
253 else
254 waddstr(win, str);
257 void
258 RefreshStringObj(StringObj *so)
260 * Desc: redraw the object
263 char tmp[512];
265 wmove(so->win, so->y, so->x+1);
266 wattrset(so->win, dialog_attr);
267 waddstr(so->win, so->title);
269 draw_box(so->win, so->y+1, so->x, 3, so->w, dialog_attr, border_attr);
270 wattrset(so->win, item_attr);
271 wmove(so->win, so->y+2, so->x+1);
272 if (strlen(so->s) > so->w-2) {
273 strncpy(tmp, (char *) so->s + strlen(so->s) - so->w + 2, so->w - 1);
274 outstr(so->win, tmp, so->attr_mask);
275 } else {
276 outstr(so->win, so->s, so->attr_mask);
279 return;
280 } /* RefreshStringObj() */
282 StringObj *
283 NewStringObj(WINDOW *win, char *title, char *s, int y, int x, int w, int len)
285 * Desc: Initialize a new stringobj and return a pointer to it.
286 * Draw the object on the screen at the specified coordinates
289 StringObj *so;
291 /* Initialize a new object */
292 so = (StringObj *) malloc( sizeof(StringObj) );
293 if (!so) {
294 printf("NewStringObj: Error malloc'ing StringObj\n");
295 exit(-1);
297 so->title = (char *) malloc( strlen(title) + 1);
298 if (!so->title) {
299 printf("NewStringObj: Error malloc'ing so->title\n");
300 exit(-1);
302 strcpy(so->title, title);
303 so->s = s;
304 strcpy(so->s, s);
305 so->x = x;
306 so->y = y;
307 so->w = w;
308 so->len = len;
309 so->win = win;
310 so->attr_mask = DialogInputAttrs; /* Grossly use a global to avoid changing API */
312 /* Draw it on the screen */
313 RefreshStringObj(so);
315 return(so);
316 } /* NewStringObj() */
319 SelectStringObj(StringObj *so)
321 * Desc: get input using the info in <so>
324 int key;
325 char tmp[so->len+1];
327 strcpy(tmp, so->s);
328 key = line_edit(so->win, so->y+2, so->x+1,
329 so->len, so->w-2, inputbox_attr, TRUE, tmp, so->attr_mask);
330 if ((key == '\n') || (key == '\r') || (key == '\t') || key == (KEY_BTAB) ) {
331 strcpy(so->s, tmp);
333 RefreshStringObj(so);
334 if (key == ESC) {
335 return(SEL_ESC);
337 if (key == '\t') {
338 return(SEL_TAB);
340 if ( (key == KEY_BTAB) || (key == KEY_F(2)) ) {
341 return(SEL_BACKTAB);
343 if ((key == '\n') || (key == '\r')) {
344 return(SEL_CR);
346 return(key);
347 } /* SelectStringObj() */
350 void
351 DelStringObj(StringObj *so)
353 * Desc: Free the space occupied by <so>
356 free(so->title);
357 free(so);
359 return;
362 /***********************************************************************
364 * ListObj routines
366 ***********************************************************************/
368 void
369 DrawNames(ListObj *lo)
371 * Desc: Just refresh the names, not the surrounding box and title
374 int i, j, h, x, y;
375 char tmp[MAXPATHLEN];
377 x = lo->x + 1;
378 y = lo->y + 2;
379 h = lo->h - 2;
380 for (i=lo->scroll; i<lo->n && i<lo->scroll+h; i++) {
381 wmove(lo->win, y+i-lo->scroll, x);
382 if (lo->seld[i]) {
383 wattrset(lo->win, A_BOLD);
384 } else {
385 wattrset(lo->win, item_attr);
387 if (strlen(lo->name[i]) > lo->w-2) {
388 strncpy(tmp, lo->name[i], lo->w-2);
389 tmp[lo->w - 2] = 0;
390 waddstr(lo->win, tmp);
391 } else {
392 waddstr(lo->win, lo->name[i]);
393 for (j=strlen(lo->name[i]); j<lo->w-2; j++) waddstr(lo->win, " ");
396 wattrset(lo->win, item_attr);
397 while (i<lo->scroll+h) {
398 wmove(lo->win, y+i-lo->scroll, x);
399 for (j=0; j<lo->w-2; j++) waddstr(lo->win, " ");
400 i++;
403 return;
404 } /* DrawNames() */
406 void
407 RefreshListObj(ListObj *lo)
409 * Desc: redraw the list object
412 char perc[7];
414 /* setup the box */
415 wmove(lo->win, lo->y, lo->x+1);
416 wattrset(lo->win, dialog_attr);
417 waddstr(lo->win, lo->title);
418 draw_box(lo->win, lo->y+1, lo->x, lo->h, lo->w, dialog_attr, border_attr);
420 /* draw the names */
421 DrawNames(lo);
423 /* Draw % indication */
424 sprintf(perc, "(%3d%%)", MIN(100, (int) (100 * (lo->sel+lo->h-2) / MAX(1, lo->n))));
425 wmove(lo->win, lo->y + lo->h, lo->x + lo->w - 8);
426 wattrset(lo->win, dialog_attr);
427 waddstr(lo->win, perc);
430 return;
431 } /* RefreshListObj() */
433 ListObj *
434 NewListObj(WINDOW *win, char *title, char **list, char *listelt, int y, int x,
435 int h, int w, int n)
437 * Desc: create a listobj, draw it on the screen and return a pointer to it.
440 ListObj *lo;
441 int i;
443 /* Initialize a new object */
444 lo = (ListObj *) malloc( sizeof(ListObj) );
445 if (!lo) {
446 fprintf(stderr, "NewListObj: Error malloc'ing ListObj\n");
447 exit(-1);
449 lo->title = (char *) malloc( strlen(title) + 1);
450 if (!lo->title) {
451 fprintf(stderr, "NewListObj: Error malloc'ing lo->title\n");
452 exit(-1);
454 strcpy(lo->title, title);
455 lo->name = list;
456 if (n>0) {
457 lo->seld = (int *) malloc( n * sizeof(int) );
458 if (!lo->seld) {
459 fprintf(stderr, "NewListObj: Error malloc'ing lo->seld\n");
460 exit(-1);
462 for (i=0; i<n; i++) {
463 lo->seld[i] = FALSE;
465 } else {
466 lo->seld = NULL;
468 lo->y = y;
469 lo->x = x;
470 lo->w = w;
471 lo->h = h;
472 lo->n = n;
473 lo->scroll = 0;
474 lo->sel = 0;
475 lo->elt = listelt;
476 lo->win = win;
478 /* Draw the object on the screen */
479 RefreshListObj(lo);
481 return(lo);
482 } /* NewListObj() */
484 void
485 UpdateListObj(ListObj *lo, char **list, int n)
487 * Desc: Update the list in the listobject with the provided list
488 * Pre: lo->name "has been freed"
489 * "(A i: 0<=i<lo->n: "lo->name[i] has been freed")"
492 int i;
494 if (lo->seld) {
495 free(lo->seld);
498 /* Rewrite the list in the object */
499 lo->name = list;
500 if (n>0) {
501 lo->seld = (int *) malloc( n * sizeof(int) );
502 if (!lo->seld) {
503 fprintf(stderr, "UpdateListObj: Error malloc'ing lo->seld\n");
504 exit(-1);
506 for (i=0; i<n; i++) {
507 lo->seld[i] = FALSE;
509 } else {
510 lo->seld = NULL;
512 lo->n = n;
513 lo->scroll = 0;
514 lo->sel = 0;
516 /* Draw the object on the screen */
517 RefreshListObj(lo);
519 return;
520 } /* UpdateListObj() */
523 SelectListObj(ListObj *lo)
525 * Desc: get a listname (or listnames), TAB to move on, or ESC ESC to exit
526 * Pre: lo->n >= 1
529 int key, sel_x, sel_y, quit;
530 char tmp[MAXPATHLEN];
531 char perc[4];
533 sel_x = lo->x+1;
534 sel_y = lo->y + 2 + lo->sel - lo->scroll;
536 if (lo->n == 0) return(SEL_TAB);
538 keypad(lo->win, TRUE);
540 /* Draw current selection in inverse video */
541 wmove(lo->win, sel_y, sel_x);
542 wattrset(lo->win, item_selected_attr);
543 waddstr(lo->win, lo->name[lo->sel]);
545 key = wgetch(lo->win);
546 quit = FALSE;
547 while ((key != '\t') && (key != '\n') && (key != '\r')
548 && (key != ESC) && (key != KEY_F(1)) && (key != '?') && !quit) {
549 /* first draw current item in normal video */
550 wmove(lo->win, sel_y, sel_x);
551 if (lo->seld[lo->sel]) {
552 wattrset(lo->win, A_BOLD);
553 } else {
554 wattrset(lo->win, item_attr);
556 if (strlen(lo->name[lo->sel]) > lo->w - 2) {
557 strncpy(tmp, lo->name[lo->sel], lo->w - 2);
558 tmp[lo->w - 2] = 0;
559 waddstr(lo->win, tmp);
560 } else {
561 waddstr(lo->win, lo->name[lo->sel]);
564 switch (key) {
565 case KEY_DOWN:
566 case ctrl('n'):
567 if (sel_y < lo->y + lo->h-1) {
568 if (lo->sel < lo->n-1) {
569 sel_y++;
570 lo->sel++;
572 } else {
573 if (lo->sel < lo->n-1) {
574 lo->sel++;
575 lo->scroll++;
576 DrawNames(lo);
577 wrefresh(lo->win);
580 break;
581 case KEY_UP:
582 case ctrl('p'):
583 if (sel_y > lo->y+2) {
584 if (lo->sel > 0) {
585 sel_y--;
586 lo->sel--;
588 } else {
589 if (lo->sel > 0) {
590 lo->sel--;
591 lo->scroll--;
592 DrawNames(lo);
593 wrefresh(lo->win);
596 break;
597 case KEY_HOME:
598 case ctrl('a'):
599 lo->sel = 0;
600 lo->scroll = 0;
601 sel_y = lo->y + 2;
602 DrawNames(lo);
603 wrefresh(lo->win);
604 break;
605 case KEY_END:
606 case ctrl('e'):
607 if (lo->n < lo->h - 3) {
608 lo->sel = lo->n-1;
609 lo->scroll = 0;
610 sel_y = lo->y + 2 + lo->sel - lo->scroll;
611 } else {
612 /* more than one page of list */
613 lo->sel = lo->n-1;
614 lo->scroll = lo->n-1 - (lo->h-3);
615 sel_y = lo->y + 2 + lo->sel - lo->scroll;
616 DrawNames(lo);
617 wrefresh(lo->win);
619 break;
620 case KEY_NPAGE:
621 case ctrl('f'):
622 lo->sel += lo->h - 2;
623 if (lo->sel >= lo->n) lo->sel = lo->n - 1;
624 lo->scroll += lo->h - 2;
625 if (lo->scroll >= lo->n - 1) lo->scroll = lo->n - 1;
626 if (lo->scroll < 0) lo->scroll = 0;
627 sel_y = lo->y + 2 + lo->sel - lo->scroll;
628 DrawNames(lo);
629 wrefresh(lo->win);
630 break;
631 case KEY_PPAGE:
632 case ctrl('b'):
633 lo->sel -= lo->h - 2;
634 if (lo->sel < 0) lo->sel = 0;
635 lo->scroll -= lo->h - 2;
636 if (lo->scroll < 0) lo->scroll = 0;
637 sel_y = lo->y + 2 + lo->sel - lo->scroll;
638 DrawNames(lo);
639 wrefresh(lo->win);
640 break;
641 default:
642 quit = TRUE;
643 break;
645 /* Draw % indication */
646 sprintf(perc, "(%3d%%)", MIN(100, (int)
647 (100 * (lo->sel+lo->h - 2) / MAX(1, lo->n))));
648 wmove(lo->win, lo->y + lo->h, lo->x + lo->w - 8);
649 wattrset(lo->win, dialog_attr);
650 waddstr(lo->win, perc);
652 /* draw current item in inverse */
653 wmove(lo->win, sel_y, sel_x);
654 wattrset(lo->win, item_selected_attr);
655 if (strlen(lo->name[lo->sel]) > lo->w - 2) {
656 /* when printing in inverse video show the last characters in the */
657 /* name that will fit in the window */
658 strncpy(tmp,
659 lo->name[lo->sel] + strlen(lo->name[lo->sel]) - (lo->w - 2),
660 lo->w - 2);
661 tmp[lo->w - 2] = 0;
662 waddstr(lo->win, tmp);
663 } else {
664 waddstr(lo->win, lo->name[lo->sel]);
666 if (!quit) key = wgetch(lo->win);
669 if (key == ESC) {
670 return(SEL_ESC);
672 if (key == '\t') {
673 return(SEL_TAB);
675 if ((key == KEY_BTAB) || (key == ctrl('b'))) {
676 return(SEL_BACKTAB);
678 if ((key == '\n') || (key == '\r')) {
679 strcpy(lo->elt, lo->name[lo->sel]);
680 return(SEL_CR);
682 return(key);
683 } /* SelectListObj() */
685 void
686 DelListObj(ListObj *lo)
688 * Desc: Free the space occupied by the listobject
691 free(lo->title);
692 if (lo->seld != NULL) free(lo->seld);
693 free(lo);
695 return;
696 } /* DelListObj() */
698 void
699 MarkCurrentListObj(ListObj *lo)
701 * Desc: mark the current item for the selection list
704 lo->seld[lo->sel] = !(lo->seld[lo->sel]);
705 DrawNames(lo);
707 return;
708 } /* MarkCurrentListObj() */
710 void
711 MarkAllListObj(ListObj *lo)
713 * Desc: mark all items
716 int i;
718 for (i=0; i<lo->n; i++) {
719 lo->seld[i] = TRUE;
721 DrawNames(lo);
723 return;
724 } /* MarkAllListObj() */
726 void
727 UnMarkAllListObj(ListObj *lo)
729 * Desc: unmark all items
732 int i;
734 for (i=0; i<lo->n; i++) {
735 lo->seld[i] = FALSE;
737 DrawNames(lo);
739 return;
740 } /* UnMarkAllListObj() */
743 /***********************************************************************
745 * ButtonObj routines
747 ***********************************************************************/
750 void
751 RefreshButtonObj(ButtonObj *bo)
753 * Desc: redraw the button
756 draw_box(bo->win, bo->y, bo->x, 3, bo->w, dialog_attr, border_attr);
757 print_button(bo->win, bo->title, bo->y+1, bo->x+2, FALSE);
759 return;
760 } /* RefreshButtonObj() */
762 ButtonObj *
763 NewButtonObj(WINDOW *win, char *title, int *pushed, int y, int x)
765 * Desc: Create a new button object
768 ButtonObj *bo;
770 bo = (ButtonObj *) malloc( sizeof(ButtonObj) );
772 bo->win = win;
773 bo->title = (char *) malloc( strlen(title) + 1);
774 strcpy(bo->title, title);
775 bo->x = x;
776 bo->y = y;
777 bo->w = strlen(title) + 6;
778 bo->h = 3;
779 bo->pushed = pushed;
781 RefreshButtonObj(bo);
783 return(bo);
784 } /* NewButtonObj() */
787 SelectButtonObj(ButtonObj *bo)
789 * Desc: Wait for buttonpresses or TAB's to move on, or ESC ESC
792 int key;
794 print_button(bo->win, bo->title, bo->y+1, bo->x+2, TRUE);
795 wmove(bo->win, bo->y+1, bo->x+(bo->w/2)-1);
796 key = wgetch(bo->win);
797 print_button(bo->win, bo->title, bo->y+1, bo->x+2, FALSE);
798 switch(key) {
799 case '\t':
800 return(SEL_TAB);
801 break;
802 case KEY_BTAB:
803 case ctrl('b'):
804 return(SEL_BACKTAB);
805 case '\n':
806 case '\r':
807 *(bo->pushed) = TRUE;
808 return(SEL_BUTTON);
809 break;
810 case ESC:
811 return(SEL_ESC);
812 break;
813 default:
814 return(key);
815 break;
817 } /* SelectButtonObj() */
819 void
820 DelButtonObj(ButtonObj *bo)
822 * Desc: Free the space occupied by <bo>
825 free(bo->title);
826 free(bo);
828 return;
829 } /* DelButtonObj() */