]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/dialog/progressbox.c
Implement pci_enable_msi() and pci_disable_msi() in the LinuxKPI.
[FreeBSD/FreeBSD.git] / contrib / dialog / progressbox.c
1 /*
2  *  $Id: progressbox.c,v 1.47 2018/06/21 09:14:47 tom Exp $
3  *
4  *  progressbox.c -- implements the progress box
5  *
6  *  Copyright 2006-2014,2018    Thomas E. Dickey
7  *  Copyright 2005              Valery Reznic
8  *
9  *  This program is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU Lesser General Public License as
11  *  published by the Free Software Foundation; either version 2.1 of the
12  *  License, or (at your option) any later version.
13  *
14  *  This program is distributed in the hope that it will be useful, but
15  *  WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  *  Lesser General Public License for more details.
18  *
19  *  You should have received a copy of the GNU Lesser General Public
20  *  License along with this program; if not, write to
21  *      Free Software Foundation, Inc.
22  *      51 Franklin St., Fifth Floor
23  *      Boston, MA 02110, USA.
24  */
25
26 #include <dialog.h>
27 #include <dlg_keys.h>
28
29 #ifdef KEY_RESIZE
30 #include <errno.h>
31 #endif
32
33 #define MIN_HIGH (4)
34 #define MIN_WIDE (10 + 2 * (2 + MARGIN))
35
36 #ifdef KEY_RESIZE
37 typedef struct _wrote {
38     struct _wrote *link;
39     char *text;
40 } WROTE;
41 #endif
42
43 typedef struct {
44     DIALOG_CALLBACK obj;
45     WINDOW *text;
46     char *prompt;
47     int high, wide;
48     int old_high, old_wide;
49     char line[MAX_LEN + 1];
50     int is_eof;
51 #ifdef KEY_RESIZE
52     WROTE *wrote;
53 #endif
54 } MY_OBJ;
55
56 static void
57 free_obj(MY_OBJ * obj)
58 {
59     dlg_del_window(obj->obj.win);
60     free(obj->prompt);
61 #ifdef KEY_RESIZE
62     while (obj->wrote) {
63         WROTE *wrote = obj->wrote;
64         obj->wrote = wrote->link;
65         free(wrote->text);
66         free(wrote);
67     }
68 #endif
69     free(obj);
70 }
71
72 static void
73 restart_obj(MY_OBJ * obj)
74 {
75     free(obj->prompt);
76     obj->high = obj->old_high;
77     obj->wide = obj->old_wide;
78     dlg_clear();
79     dlg_del_window(obj->obj.win);
80 }
81
82 static void
83 start_obj(MY_OBJ * obj, const char *title, const char *cprompt)
84 {
85     int y, x, thigh;
86     int i;
87
88     obj->prompt = dlg_strclone(cprompt);
89     dlg_tab_correct_str(obj->prompt);
90     dlg_auto_size(title, obj->prompt, &obj->high, &obj->wide, MIN_HIGH, MIN_WIDE);
91
92     dlg_print_size(obj->high, obj->wide);
93     dlg_ctl_size(obj->high, obj->wide);
94
95     x = dlg_box_x_ordinate(obj->wide);
96     y = dlg_box_y_ordinate(obj->high);
97     thigh = obj->high - (2 * MARGIN);
98
99     obj->obj.win = dlg_new_window(obj->high, obj->wide, y, x);
100
101     dlg_draw_box2(obj->obj.win,
102                   0, 0,
103                   obj->high, obj->wide,
104                   dialog_attr,
105                   border_attr,
106                   border2_attr);
107     dlg_draw_title(obj->obj.win, title);
108     dlg_draw_helpline(obj->obj.win, FALSE);
109
110     if (obj->prompt[0] != '\0') {
111         int y2, x2;
112
113         dlg_attrset(obj->obj.win, dialog_attr);
114         dlg_print_autowrap(obj->obj.win, obj->prompt, obj->high, obj->wide);
115         getyx(obj->obj.win, y2, x2);
116         (void) x2;
117         ++y2;
118         wmove(obj->obj.win, y2, MARGIN);
119         for (i = 0; i < getmaxx(obj->obj.win) - 2 * MARGIN; i++)
120             (void) waddch(obj->obj.win, dlg_boxchar(ACS_HLINE));
121         y += y2;
122         thigh -= y2;
123     }
124
125     /* Create window for text region, used for scrolling text */
126     obj->text = dlg_sub_window(obj->obj.win,
127                                thigh,
128                                obj->wide - (2 * MARGIN),
129                                y + MARGIN,
130                                x + MARGIN);
131
132     (void) wrefresh(obj->obj.win);
133
134     (void) wmove(obj->obj.win, getmaxy(obj->text), (MARGIN + 1));
135     (void) wnoutrefresh(obj->obj.win);
136
137     dlg_attr_clear(obj->text, getmaxy(obj->text), getmaxx(obj->text), dialog_attr);
138 }
139
140 /*
141  * Return current line of text.
142  */
143 static char *
144 get_line(MY_OBJ * obj, int *restart)
145 {
146     FILE *fp = obj->obj.input;
147     int col = 0;
148     int j, tmpint, ch;
149     char *result = obj->line;
150
151     *restart = 0;
152     for (;;) {
153         ch = getc(fp);
154 #ifdef KEY_RESIZE
155         /* SIGWINCH may have interrupted this - try to ignore if resizable */
156         if (ferror(fp)) {
157             switch (errno) {
158             case EINTR:
159                 clearerr(fp);
160                 continue;
161             default:
162                 break;
163             }
164         }
165 #endif
166         if (feof(fp) || ferror(fp)) {
167             obj->is_eof = 1;
168             if (!col) {
169                 result = NULL;
170             }
171             break;
172         }
173         if (ch == '\n')
174             break;
175         if (ch == '\r')
176             break;
177         if (col >= MAX_LEN)
178             continue;
179         if ((ch == TAB) && (dialog_vars.tab_correct)) {
180             tmpint = dialog_state.tab_len
181                 - (col % dialog_state.tab_len);
182             for (j = 0; j < tmpint; j++) {
183                 if (col < MAX_LEN) {
184                     obj->line[col] = ' ';
185                     ++col;
186                 } else {
187                     break;
188                 }
189             }
190         } else {
191             obj->line[col] = (char) ch;
192             ++col;
193         }
194     }
195
196     obj->line[col] = '\0';
197
198 #ifdef KEY_RESIZE
199     if (result != NULL) {
200         WINDOW *win = obj->text;
201         WROTE *wrote = dlg_calloc(WROTE, 1);
202
203         if (wrote != 0) {
204             wrote->text = dlg_strclone(obj->line);
205             wrote->link = obj->wrote;
206             obj->wrote = wrote;
207         }
208
209         nodelay(win, TRUE);
210         if ((ch = wgetch(win)) == KEY_RESIZE) {
211             *restart = 1;
212         }
213         nodelay(win, FALSE);
214     }
215 #endif
216     return result;
217 }
218
219 /*
220  * Print a new line of text.
221  */
222 static void
223 print_line(MY_OBJ * obj, const char *line, int row)
224 {
225     int width = obj->wide - (2 * MARGIN);
226     int limit = MIN((int) strlen(line), width - 2);
227
228     (void) wmove(obj->text, row, 0);    /* move cursor to correct line */
229     wprintw(obj->text, " %.*s", limit, line);
230     wclrtoeol(obj->text);
231 }
232
233 #ifdef KEY_RESIZE
234 static int
235 wrote_size(MY_OBJ * obj, int want)
236 {
237     int result = 0;
238     WROTE *wrote = obj->wrote;
239     while (wrote != NULL && want > 0) {
240         wrote = wrote->link;
241         want--;
242         result++;
243     }
244     return result;
245 }
246
247 static const char *
248 wrote_data(MY_OBJ * obj, int want)
249 {
250     const char *result = NULL;
251     WROTE *wrote = obj->wrote;
252     while (wrote != NULL && want > 0) {
253         result = wrote->text;
254         wrote = wrote->link;
255         want--;
256     }
257     return result;
258 }
259
260 static int
261 reprint_lines(MY_OBJ * obj, int buttons)
262 {
263     int want = getmaxy(obj->text) - (buttons ? 2 : 0);
264     int have = wrote_size(obj, want);
265     int n;
266     for (n = 0; n < have; ++n) {
267         print_line(obj, wrote_data(obj, have - n), n);
268     }
269     (void) wrefresh(obj->text);
270     return have;
271 }
272 #endif
273
274 static int
275 pause_for_ok(MY_OBJ * obj, const char *title, const char *cprompt)
276 {
277     /* *INDENT-OFF* */
278     static DLG_KEYS_BINDING binding[] = {
279         HELPKEY_BINDINGS,
280         ENTERKEY_BINDINGS,
281         TRAVERSE_BINDINGS,
282         END_KEYS_BINDING
283     };
284     /* *INDENT-ON* */
285
286     int button;
287     int key = 0, fkey;
288     int result = DLG_EXIT_UNKNOWN;
289     const char **buttons = dlg_ok_label();
290     int check;
291     bool save_nocancel = dialog_vars.nocancel;
292     bool redraw = TRUE;
293
294     dialog_vars.nocancel = TRUE;
295     button = dlg_default_button();
296
297 #ifdef KEY_RESIZE
298   restart:
299 #endif
300
301     dlg_register_window(obj->obj.win, "progressbox", binding);
302     dlg_register_buttons(obj->obj.win, "progressbox", buttons);
303
304     dlg_draw_bottom_box2(obj->obj.win, border_attr, border2_attr, dialog_attr);
305
306     while (result == DLG_EXIT_UNKNOWN) {
307         if (redraw) {
308             redraw = FALSE;
309             if (button < 0)
310                 button = 0;
311             dlg_draw_buttons(obj->obj.win,
312                              obj->high - 2, 0,
313                              buttons, button,
314                              FALSE, obj->wide);
315         }
316
317         key = dlg_mouse_wgetch(obj->obj.win, &fkey);
318         if (dlg_result_key(key, fkey, &result))
319             break;
320
321         if (!fkey && (check = dlg_char_to_button(key, buttons)) >= 0) {
322             result = dlg_ok_buttoncode(check);
323             break;
324         }
325
326         if (fkey) {
327             switch (key) {
328             case DLGK_FIELD_NEXT:
329                 button = dlg_next_button(buttons, button);
330                 redraw = TRUE;
331                 break;
332             case DLGK_FIELD_PREV:
333                 button = dlg_prev_button(buttons, button);
334                 redraw = TRUE;
335                 break;
336             case DLGK_ENTER:
337                 result = dlg_ok_buttoncode(button);
338                 break;
339 #ifdef KEY_RESIZE
340             case KEY_RESIZE:
341                 dlg_will_resize(obj->obj.win);
342                 restart_obj(obj);
343                 start_obj(obj, title, cprompt);
344                 reprint_lines(obj, TRUE);
345                 redraw = TRUE;
346                 goto restart;
347 #endif
348             default:
349                 if (is_DLGK_MOUSE(key)) {
350                     result = dlg_ok_buttoncode(key - M_EVENT);
351                     if (result < 0)
352                         result = DLG_EXIT_OK;
353                 } else {
354                     beep();
355                 }
356                 break;
357             }
358
359         } else {
360             beep();
361         }
362     }
363     dlg_mouse_free_regions();
364     dlg_unregister_window(obj->obj.win);
365
366     dialog_vars.nocancel = save_nocancel;
367     return result;
368 }
369
370 int
371 dlg_progressbox(const char *title,
372                 const char *cprompt,
373                 int height,
374                 int width,
375                 int pauseopt,
376                 FILE *fp)
377 {
378     int i;
379     MY_OBJ *obj;
380     int again = 0;
381     int toprow = 0;
382     int result;
383
384     DLG_TRACE(("# progressbox args:\n"));
385     DLG_TRACE2S("title", title);
386     DLG_TRACE2S("message", cprompt);
387     DLG_TRACE2N("height", height);
388     DLG_TRACE2N("width", width);
389     DLG_TRACE2N("pause", pauseopt);
390     DLG_TRACE2N("fp", fp ? fileno(fp) : -1);
391
392     obj = dlg_calloc(MY_OBJ, 1);
393     assert_ptr(obj, "dlg_progressbox");
394     obj->obj.input = fp;
395
396     obj->high = height;
397     obj->wide = width;
398
399 #ifdef KEY_RESIZE
400     obj->old_high = height;
401     obj->old_wide = width;
402
403     curs_set(0);
404   restart:
405 #endif
406
407     start_obj(obj, title, cprompt);
408 #ifdef KEY_RESIZE
409     if (again) {
410         toprow = reprint_lines(obj, FALSE);
411     }
412 #endif
413
414     for (i = toprow; get_line(obj, &again); i++) {
415 #ifdef KEY_RESIZE
416         if (again) {
417             dlg_will_resize(obj->obj.win);
418             restart_obj(obj);
419             goto restart;
420         }
421 #endif
422         if (i < getmaxy(obj->text)) {
423             print_line(obj, obj->line, i);
424         } else {
425             scrollok(obj->text, TRUE);
426             scroll(obj->text);
427             scrollok(obj->text, FALSE);
428             print_line(obj, obj->line, getmaxy(obj->text) - 1);
429         }
430         (void) wrefresh(obj->text);
431         if (obj->is_eof)
432             break;
433     }
434
435     dlg_trace_win(obj->obj.win);
436     curs_set(1);
437
438     if (pauseopt) {
439         int need = 1 + MARGIN;
440         int base = getmaxy(obj->text) - need;
441         if (i >= base) {
442             i -= base;
443             if (i > need)
444                 i = need;
445             if (i > 0) {
446                 scrollok(obj->text, TRUE);
447             }
448             wscrl(obj->text, i);
449         }
450         (void) wrefresh(obj->text);
451         result = pause_for_ok(obj, title, cprompt);
452     } else {
453         wrefresh(obj->obj.win);
454         result = DLG_EXIT_OK;
455     }
456
457     free_obj(obj);
458
459     return result;
460 }
461
462 /*
463  * Display text from a stdin in a scrolling window.
464  */
465 int
466 dialog_progressbox(const char *title, const char *cprompt, int height, int width)
467 {
468     int result;
469     result = dlg_progressbox(title,
470                              cprompt,
471                              height,
472                              width,
473                              FALSE,
474                              dialog_state.pipe_input);
475     dialog_state.pipe_input = 0;
476     return result;
477 }