Fix -j builds for gcc-3.4. The .nx build in cc_tools was breaking
[dragonfly.git] / gnu / lib / libdialog / kernel.c
1 /*
2  *  dialog - Display simple dialog boxes from shell scripts
3  *
4  *  AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
5  *
6  *  This program is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU General Public License
8  *  as published by the Free Software Foundation; either version 2
9  *  of the License, or (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  *
20  *
21  *  HISTORY:
22  *
23  *  17/12/93 - Version 0.1 released.
24  *
25  *  19/12/93 - menu will now scroll if there are more items than can fit
26  *             on the screen.
27  *           - added 'checklist', a dialog box with a list of options that
28  *             can be turned on or off. A list of options that are on is
29  *             returned on exit.
30  *
31  *  20/12/93 - Version 0.15 released.
32  *
33  *  29/12/93 - Incorporated patch from Patrick J. Volkerding
34  *             (volkerdi@mhd1.moorhead.msus.edu) that made these changes:
35  *             - increased MAX_LEN to 2048
36  *             - added 'infobox', equivalent to a message box without pausing
37  *             - added option '--clear' that will clear the screen
38  *             - Explicit line breaking when printing prompt text can be
39  *               invoked by real newline '\n' besides the string "\n"
40  *           - an optional parameter '--title <string>' can be used to
41  *             specify a title string for the dialog box
42  *
43  *  03/01/94 - added 'textbox', a dialog box for displaying text from a file.
44  *           - Version 0.2 released.
45  *
46  *  04/01/94 - some fixes and improvements for 'textbox':
47  *             - fixed a bug that will cause a segmentation violation when a
48  *               line is longer than MAX_LEN characters. Lines will now be
49  *               truncated if they are longer than MAX_LEN characters.
50  *             - removed wrefresh() from print_line(). This will increase
51  *               efficiency of print_page() which calls print_line().
52  *             - display current position in the form of percentage into file.
53  *           - Version 0.21 released.
54  *
55  *  05/01/94 - some changes for faster screen update.
56  *
57  *  07/01/94 - much more flexible color settings. Can use all 16 colors
58  *             (8 normal, 8 highlight) of the Linux console.
59  *
60  *  08/01/94 - added run-time configuration using configuration file.
61  *
62  *  09/01/94 - some minor bug fixes and cleanups for menubox, checklist and
63  *             textbox.
64  *
65  *  11/01/94 - added a man page.
66  *
67  *  13/01/94 - some changes for easier porting to other Unix systems (tested
68  *             on Ultrix, SunOS and HPUX)
69  *           - Version 0.3 released.
70  *
71  *  08/06/94 - Patches by Stuart Herbert - S.Herbert@shef.ac.uk
72  *             Fixed attr_clear and the textbox stuff to work with ncurses 1.8.5
73  *             Fixed the wordwrap routine - it'll actually wrap properly now
74  *             Added a more 3D look to everything - having your own rc file could
75  *               prove 'interesting' to say the least :-)
76  *             Added radiolist option
77  *           - Version 0.4 released.
78  *
79  * $FreeBSD: src/gnu/lib/libdialog/kernel.c,v 1.26.6.1 2003/02/15 05:32:04 kris Exp $
80  * $DragonFly: src/gnu/lib/libdialog/kernel.c,v 1.2 2003/06/17 04:25:43 dillon Exp $
81  */
82
83 #define __DIALOG_MAIN__
84
85 #include <dialog.h>
86 #include <err.h>
87 #include "dialog.priv.h"
88 #ifdef HAVE_NCURSES
89 #include "colors.h"
90 #endif
91
92 /* These are two "secret" globals that can be fiddled to make a dialog
93  * come up someplace other than a "centered" calculation for X,Y
94  */
95 int DialogX, DialogY;
96
97 /* This "secret" global allows you to change the behavior of an input field */
98 int DialogInputAttrs;
99
100 /*
101  * Do some initialization for dialog
102  */
103 void init_dialog(void)
104 {
105
106   if (issetugid()) {
107         errx(1, "libdialog is unsafe to use in setugid applications");
108   }
109
110 #if defined(LOCALE)
111   (void) setlocale(LC_ALL, "");
112 #endif
113
114 #ifdef HAVE_NCURSES
115   if (parse_rc() == -1)    /* Read the configuration file */
116     exit(-1);
117 #endif
118
119   if (initscr() == NULL) { /* Init curses */
120     fprintf(stderr, "\nCurses initialization error.\n");
121     exit(-1);
122   }
123   keypad(stdscr, TRUE);
124   cbreak();
125   noecho();
126
127 #ifdef HAVE_NCURSES
128   if (use_colors || use_shadow)    /* Set up colors */
129     color_setup();
130 #endif
131
132   /* Set screen to screen attribute */
133   dialog_clear_norefresh();
134   DialogX = DialogY = 0;
135 }
136 /* End of init_dialog() */
137
138
139 #ifdef HAVE_NCURSES
140 /*
141  * Setup for color display
142  */
143 void color_setup(void)
144 {
145   int i;
146
147   if (has_colors()) {    /* Terminal supports color? */
148     start_color();
149
150     /* Initialize color pairs */
151     for (i = 0; i < ATTRIBUTE_COUNT; i++)
152       init_pair(i+1, color_table[i][0], color_table[i][1]);
153
154     /* Setup color attributes */
155     for (i = 0; i < ATTRIBUTE_COUNT; i++)
156       attributes[i] = C_ATTR(color_table[i][2], i+1);
157   }
158 }
159 /* End of color_setup() */
160 #endif
161
162
163 /*
164  * Set window to attribute 'attr'
165  */
166 void attr_clear(WINDOW *win, int height, int width, chtype attr)
167 {
168   int i, j;
169
170   wattrset(win, attr);    /* Set window to attribute 'attr' */
171   for (i = 0; i < height; i++) {
172     wmove(win, i, 0);
173     for (j = 0; j < width; j++)
174       waddch(win, ' ');
175   }
176 }
177 /* End of attr_clear() */
178
179
180 /*
181  * Print a string of text in a window, automatically wrap around to the
182  * next line if the string is too long to fit on one line. Note that the
183  * string may contain "\n" to represent a newline character or the real
184  * newline '\n', but in that case, auto wrap around will be disabled.
185  */
186 void print_autowrap(WINDOW *win, unsigned char *prompt, int height, int width, int maxwidth, int y, int x, int center, int rawmode)
187 {
188   int cur_x, cur_y, i;
189   unsigned char tempstr[MAX_LEN+1], *word, *tempptr, *tempptr1;
190   chtype ostuff[132], attrs = 0, init_bottom = 0;
191
192   wsetscrreg(win, y, height);
193   getyx(win, cur_y, cur_x);
194
195   strncpy(tempstr, prompt, MAX_LEN);
196   tempstr[MAX_LEN] = '\0';
197   if ((!rawmode && strstr(tempstr, "\\n") != NULL) ||
198       (strchr(tempstr, '\n') != NULL)) {    /* Prompt contains "\n" or '\n' */
199     word = tempstr;
200     while (1) {
201       tempptr = rawmode ? NULL : strstr(word, "\\n");
202       tempptr1 = strchr(word, '\n');
203       if (tempptr == NULL && tempptr1 == NULL)
204         break;
205       else if (tempptr == NULL) {    /* No more "\n" */
206         tempptr = tempptr1;
207         tempptr[0] = '\0';
208       }
209       else if (tempptr1 == NULL) {    /* No more '\n' */
210         tempptr[0] = '\0';
211         tempptr++;
212       }
213       else {    /* Prompt contains both "\n" and '\n' */
214         if (strlen(tempptr)-2 < strlen(tempptr1)-1) {
215           tempptr = tempptr1;
216           tempptr[0] = '\0';
217         }
218         else {
219           tempptr[0] = '\0';
220           tempptr++;
221         }
222       }
223
224       waddstr(win, word);
225       word = tempptr + 1;
226       if (++cur_y > height) {
227         cur_y--;
228         if (!init_bottom) {
229           for (i = 0; i < x; i++)
230             ostuff[i] = mvwinch(win, cur_y, i);
231           for (i = width; i < maxwidth; i++)
232             ostuff[i] = mvwinch(win, cur_y, i);
233           attrs = getattrs(win);
234           init_bottom = 1;
235         }
236         scrollok(win, TRUE);
237         scroll(win);
238         scrollok(win, FALSE);
239         wmove(win, cur_y, 0);
240         for (i = 0; i < x; i++) {
241           wattrset(win, ostuff[i]&A_ATTRIBUTES);
242           waddch(win, ostuff[i]);
243         }
244         wattrset(win, attrs);
245         for ( ; i < width; i++)
246           waddch(win, ' ');
247         for ( ; i < maxwidth; i++) {
248           wattrset(win, ostuff[i]&A_ATTRIBUTES);
249           waddch(win, ostuff[i]);
250         }
251         wattrset(win, attrs);
252         wrefresh(win);
253       }
254       wmove(win, cur_y, cur_x = x);
255     }
256     waddstr(win, word);
257   }
258   else if (center && strlen(tempstr) <= width-x*2) {    /* If prompt is short */
259     wmove(win, cur_y, (width - strlen(tempstr)) / 2);
260     waddstr(win, tempstr);
261   }
262   else if (!center && strlen(tempstr) <= width-cur_x) {    /* If prompt is short */
263     waddstr(win, tempstr);
264   }
265   else {
266     char *p = tempstr;
267
268     /* Print prompt word by word, wrap around if necessary */
269     while ((word = strsep(&p, "\t\n ")) != NULL) {
270       int loop;
271       unsigned char sc;
272
273       if (*word == '\0')
274         continue;
275       do {
276         loop = 0;
277         if (cur_x+strlen(word) >= width+1) {    /* wrap around to next line */
278           if (x+strlen(word) >= width+1) {
279             sc = word[width-cur_x-1];
280             word[width-cur_x-1] = '\0';
281             wmove(win, cur_y, cur_x);
282             waddstr(win, word);
283             word[width-cur_x-1] = sc;
284             word += width-cur_x-1;
285             getyx(win, cur_y, cur_x);
286             loop = 1;
287           }
288           cur_y++;
289           cur_x = x;
290           if (cur_y > height) {
291             cur_y--;
292             if (!init_bottom) {
293               for (i = 0; i < x; i++)
294                 ostuff[i] = mvwinch(win, cur_y, i);
295               for (i = width; i < maxwidth; i++)
296                 ostuff[i] = mvwinch(win, cur_y, i);
297               attrs = getattrs(win);
298               init_bottom = 1;
299             }
300             scrollok(win, TRUE);
301             scroll(win);
302             scrollok(win, FALSE);
303             wmove(win, cur_y, 0);
304             for (i = 0; i < x; i++) {
305               wattrset(win, ostuff[i]&A_ATTRIBUTES);
306               waddch(win, ostuff[i]);
307             }
308             wattrset(win, attrs);
309             for ( ; i < width; i++)
310               waddch(win, ' ');
311             for ( ; i < maxwidth; i++) {
312               wattrset(win, ostuff[i]&A_ATTRIBUTES);
313               waddch(win, ostuff[i]);
314             }
315             wattrset(win, attrs);
316             wrefresh(win);
317           }
318         }
319       }
320       while(loop);
321       wmove(win, cur_y, cur_x);
322       waddstr(win, word);
323       getyx(win, cur_y, cur_x);
324       cur_x++;
325     }
326   }
327 }
328 /* End of print_autowrap() */
329
330
331 /*
332  * Print a button
333  */
334 void print_button(WINDOW *win, unsigned char *label, int y, int x, int selected)
335 {
336   int i, temp;
337
338   wmove(win, y, x);
339   wattrset(win, selected ? button_active_attr : button_inactive_attr);
340   waddstr(win, selected ? "[" : " ");
341   temp = strspn(label, " ");
342   label += temp;
343   for (i = 0; i < temp; i++)
344     waddch(win, ' ');
345   wattrset(win, selected ? button_key_active_attr : button_key_inactive_attr);
346   waddch(win, label[0]);
347   wattrset(win, selected ? button_active_attr : button_inactive_attr);
348   waddstr(win, label+1);
349   waddstr(win, selected ? "]" : " ");
350   wmove(win, y, x+temp+1);
351 }
352 /* End of print_button() */
353
354
355 /*
356  * Draw a rectangular box with line drawing characters
357  */
358 void draw_box(WINDOW *win, int y, int x, int height, int width, chtype box, chtype border)
359 {
360   int i, j;
361
362   wattrset(win, 0);
363   for (i = 0; i < height; i++) {
364     wmove(win, y + i, x);
365     for (j = 0; j < width; j++)
366       if (!i && !j)
367         waddch(win, border | ACS_ULCORNER);
368       else if (i == height-1 && !j)
369         waddch(win, border | ACS_LLCORNER);
370       else if (!i && j == width-1)
371         waddch(win, box | ACS_URCORNER);
372       else if (i == height-1 && j == width-1)
373         waddch(win, box | ACS_LRCORNER);
374       else if (!i)
375         waddch(win, border | ACS_HLINE);
376       else if (i == height-1)
377         waddch(win, box | ACS_HLINE);
378       else if (!j)
379         waddch(win, border | ACS_VLINE);
380       else if (j == width-1)
381         waddch(win, box | ACS_VLINE);
382       else
383         waddch(win, box | ' ');
384   }
385 }
386 /* End of draw_box() */
387
388
389 #ifdef HAVE_NCURSES
390 /*
391  * Draw shadows along the right and bottom edge to give a more 3D look
392  * to the boxes
393  */
394 void draw_shadow(WINDOW *win, int y, int x, int height, int width)
395 {
396   int i,sx,sy;
397   chtype attrs;
398
399   if (has_colors()) {    /* Whether terminal supports color? */
400     getbegyx(win,sy,sx);
401     attrs = getattrs(win);
402     if (y+height < getmaxy(win)) {
403         /* small touch */
404         wattrset(win, A_INVIS);
405         wmove(win, y + height, x + 2);
406         for (i = 0; i < width; i++)
407             if (i+x+2 < getmaxx(win))
408                waddch(win, ' ');
409         /* end touch */
410         wattrset(win, shadow_attr);
411         wmove(win, y + height, x + 2);
412         for (i = 0; i < width; i++)
413             if (i+x+2 < getmaxx(win))
414                waddch(win, mvwinch(newscr, sy+y+height, sx+x+2+i) & A_CHARTEXT);
415     }
416     if (x+width < getmaxx(win)) {
417         for (i = y + 1; i < y + height + 1; i++) {
418           if (i < getmaxy(win)) {
419               /* small touch */
420               wattrset(win, A_INVIS);
421               wmove(win, i, x + width);
422               waddch(win, ' ');
423               if (x+width+1 < getmaxx(win))
424                     waddch(win, ' ');
425               /* end touch */
426               wattrset(win, shadow_attr);
427               wmove(win, i, x + width);
428               waddch(win, mvwinch(newscr, sy+i, sx+x+width) & A_CHARTEXT);
429               if (x+width+1 < getmaxx(win))
430                     waddch(win, mvwinch(newscr, sy+i, sx+x+width+1) & A_CHARTEXT);
431           }
432         }
433     }
434     wattrset(win, attrs);
435     wnoutrefresh(win);
436   }
437 }
438 /* End of draw_shadow() */
439 #endif
440
441 void dialog_clear_norefresh(void)
442 {
443     attr_clear(stdscr, LINES, COLS, screen_attr);
444     touchwin(stdscr);
445     wnoutrefresh(stdscr);
446 }
447
448 void dialog_clear(void)
449 {
450     dialog_clear_norefresh();
451     doupdate();
452 }
453
454 void dialog_update(void)
455 {
456     refresh();
457 }
458
459 void end_dialog(void)
460 {
461     endwin();
462 }
463
464 int strwidth(const char *p)
465 {
466         int i = 0, len, incr;
467         const char *start, *s, *s1, *s2;
468
469         for (start = s = p; ; start = (s += incr)) {
470                 s1 = strchr(s, '\n');
471                 s2 = strstr(s, "\\n");
472                 if (s2 == NULL)
473                         s = s1;
474                 else if (s1 == NULL)
475                         s = s2;
476                 else
477                         s = MIN(s1, s2);
478                 if (s == NULL)
479                         break;
480                 incr = 1 + (s == s2);
481                 len = s - start;
482                 if (len > i)
483                         i = len;
484         }
485         len = strlen(start);
486         if (len > i)
487                 i = len;
488         return i;
489 }
490
491 int strheight(const char *p)
492 {
493         int i = 1, incr;
494         const char *s, *s1, *s2;
495
496         for (s = p; ; s += incr) {
497                 s1 = strchr(s, '\n');
498                 s2 = strstr(s, "\\n");
499                 if (s2 == NULL)
500                         s = s1;
501                 else if (s1 == NULL)
502                         s = s2;
503                 else
504                         s = MIN(s1, s2);
505                 if (s == NULL)
506                         break;
507                 incr = 1 + (s == s2);
508                 i++;
509         }
510         return i;
511 }
512
513 void print_arrows(WINDOW *dialog, int scroll, int menu_height, int item_no,
514                   int box_x, int box_y, int tag_x, int cur_x, int cur_y)
515 {
516     wmove(dialog, box_y, box_x + tag_x + 1);
517     wattrset(dialog, scroll ? uarrow_attr : menubox_attr);
518     waddch(dialog, scroll ? ACS_UARROW : ACS_HLINE);
519     wmove(dialog, box_y, box_x + tag_x + 2);
520     waddch(dialog, scroll ? '(' : ACS_HLINE);
521     wmove(dialog, box_y, box_x + tag_x + 3);
522     waddch(dialog, scroll ? '-' : ACS_HLINE);
523     wmove(dialog, box_y, box_x + tag_x + 4);
524     waddch(dialog, scroll ? ')' : ACS_HLINE);
525     wmove(dialog, box_y + menu_height + 1, box_x + tag_x + 1);
526     wattrset(dialog, scroll+menu_height < item_no ? darrow_attr : menubox_border_attr);
527     waddch(dialog, scroll+menu_height < item_no ? ACS_DARROW : ACS_HLINE);
528     wmove(dialog, box_y + menu_height + 1, box_x + tag_x + 2);
529     waddch(dialog, scroll+menu_height < item_no ? '(' : ACS_HLINE);
530     wmove(dialog, box_y + menu_height + 1, box_x + tag_x + 3);
531     waddch(dialog, scroll+menu_height < item_no ? '+' : ACS_HLINE);
532     wmove(dialog, box_y + menu_height + 1, box_x + tag_x + 4);
533     waddch(dialog, scroll+menu_height < item_no ? ')' : ACS_HLINE);
534     wmove(dialog, cur_y, cur_x);  /* Restore cursor position */
535 }
536