source: branches/3.2/mindi-busybox/scripts/kconfig/lxdialog/textbox.c @ 3232

Last change on this file since 3232 was 3232, checked in by bruno, 5 years ago
  • Update mindi-busybox to 1.21.1
  • Property svn:eol-style set to native
File size: 14.5 KB
Line 
1/*
2 *  textbox.c -- implements the text box
3 *
4 *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
5 *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
6 *
7 *  This program is free software; you can redistribute it and/or
8 *  modify it under the terms of the GNU General Public License
9 *  as published by the Free Software Foundation; either version 2
10 *  of the License, or (at your option) any later version.
11 *
12 *  This program is distributed in the hope that it will be useful,
13 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 *  GNU General Public License for more details.
16 *
17 *  You should have received a copy of the GNU General Public License
18 *  along with this program; if not, write to the Free Software
19 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22#include "dialog.h"
23
24static void back_lines(int n);
25static void print_page(WINDOW * win, int height, int width);
26static void print_line(WINDOW * win, int row, int width);
27static char *get_line(void);
28static void print_position(WINDOW * win, int height, int width);
29
30static int hscroll, fd, file_size, bytes_read;
31static int begin_reached = 1, end_reached, page_length;
32static char *buf, *page;
33
34/*
35 * Display text from a file in a dialog box.
36 */
37int dialog_textbox(const char *title, const char *file, int height, int width)
38{
39    int i, x, y, cur_x, cur_y, fpos, key = 0;
40    int passed_end;
41    WINDOW *dialog, *text;
42
43    /* Open input file for reading */
44    if ((fd = open(file, O_RDONLY)) == -1) {
45        endwin();
46        fprintf(stderr, "\nCan't open input file in dialog_textbox().\n");
47        exit(-1);
48    }
49    /* Get file size. Actually, 'file_size' is the real file size - 1,
50       since it's only the last byte offset from the beginning */
51    if ((file_size = lseek(fd, 0, SEEK_END)) == -1) {
52        endwin();
53        fprintf(stderr, "\nError getting file size in dialog_textbox().\n");
54        exit(-1);
55    }
56    /* Restore file pointer to beginning of file after getting file size */
57    if (lseek(fd, 0, SEEK_SET) == -1) {
58        endwin();
59        fprintf(stderr, "\nError moving file pointer in dialog_textbox().\n");
60        exit(-1);
61    }
62    /* Allocate space for read buffer */
63    if ((buf = malloc(BUF_SIZE + 1)) == NULL) {
64        endwin();
65        fprintf(stderr, "\nCan't allocate memory in dialog_textbox().\n");
66        exit(-1);
67    }
68    if ((bytes_read = read(fd, buf, BUF_SIZE)) == -1) {
69        endwin();
70        fprintf(stderr, "\nError reading file in dialog_textbox().\n");
71        exit(-1);
72    }
73    buf[bytes_read] = '\0'; /* mark end of valid data */
74    page = buf;     /* page is pointer to start of page to be displayed */
75
76    /* center dialog box on screen */
77    x = (COLS - width) / 2;
78    y = (LINES - height) / 2;
79
80    draw_shadow(stdscr, y, x, height, width);
81
82    dialog = newwin(height, width, y, x);
83    keypad(dialog, TRUE);
84
85    /* Create window for text region, used for scrolling text */
86    text = subwin(dialog, height - 4, width - 2, y + 1, x + 1);
87    wattrset(text, dialog_attr);
88    wbkgdset(text, dialog_attr & A_COLOR);
89
90    keypad(text, TRUE);
91
92    /* register the new window, along with its borders */
93    draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr);
94
95    wattrset(dialog, border_attr);
96    mvwaddch(dialog, height - 3, 0, ACS_LTEE);
97    for (i = 0; i < width - 2; i++)
98        waddch(dialog, ACS_HLINE);
99    wattrset(dialog, dialog_attr);
100    wbkgdset(dialog, dialog_attr & A_COLOR);
101    waddch(dialog, ACS_RTEE);
102
103    print_title(dialog, title, width);
104
105    print_button(dialog, " Exit ", height - 2, width / 2 - 4, TRUE);
106    wnoutrefresh(dialog);
107    getyx(dialog, cur_y, cur_x);    /* Save cursor position */
108
109    /* Print first page of text */
110    attr_clear(text, height - 4, width - 2, dialog_attr);
111    print_page(text, height - 4, width - 2);
112    print_position(dialog, height, width);
113    wmove(dialog, cur_y, cur_x);    /* Restore cursor position */
114    wrefresh(dialog);
115
116    while ((key != ESC) && (key != '\n')) {
117        key = wgetch(dialog);
118        switch (key) {
119        case 'E':   /* Exit */
120        case 'e':
121        case 'X':
122        case 'x':
123            delwin(dialog);
124            free(buf);
125            close(fd);
126            return 0;
127        case 'g':   /* First page */
128        case KEY_HOME:
129            if (!begin_reached) {
130                begin_reached = 1;
131                /* First page not in buffer? */
132                if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) {
133                    endwin();
134                    fprintf(stderr, "\nError moving file pointer in dialog_textbox().\n");
135                    exit(-1);
136                }
137                if (fpos > bytes_read) {    /* Yes, we have to read it in */
138                    if (lseek(fd, 0, SEEK_SET) == -1) {
139                        endwin();
140                        fprintf(stderr, "\nError moving file pointer in "
141                                    "dialog_textbox().\n");
142                        exit(-1);
143                    }
144                    if ((bytes_read =
145                         read(fd, buf, BUF_SIZE)) == -1) {
146                        endwin();
147                        fprintf(stderr, "\nError reading file in dialog_textbox().\n");
148                        exit(-1);
149                    }
150                    buf[bytes_read] = '\0';
151                }
152                page = buf;
153                print_page(text, height - 4, width - 2);
154                print_position(dialog, height, width);
155                wmove(dialog, cur_y, cur_x);    /* Restore cursor position */
156                wrefresh(dialog);
157            }
158            break;
159        case 'G':   /* Last page */
160        case KEY_END:
161
162            end_reached = 1;
163            /* Last page not in buffer? */
164            if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) {
165                endwin();
166                fprintf(stderr, "\nError moving file pointer in dialog_textbox().\n");
167                exit(-1);
168            }
169            if (fpos < file_size) { /* Yes, we have to read it in */
170                if (lseek(fd, -BUF_SIZE, SEEK_END) == -1) {
171                    endwin();
172                    fprintf(stderr, "\nError moving file pointer in dialog_textbox().\n");
173                    exit(-1);
174                }
175                if ((bytes_read =
176                     read(fd, buf, BUF_SIZE)) == -1) {
177                    endwin();
178                    fprintf(stderr, "\nError reading file in dialog_textbox().\n");
179                    exit(-1);
180                }
181                buf[bytes_read] = '\0';
182            }
183            page = buf + bytes_read;
184            back_lines(height - 4);
185            print_page(text, height - 4, width - 2);
186            print_position(dialog, height, width);
187            wmove(dialog, cur_y, cur_x);    /* Restore cursor position */
188            wrefresh(dialog);
189            break;
190        case 'K':   /* Previous line */
191        case 'k':
192        case KEY_UP:
193            if (!begin_reached) {
194                back_lines(page_length + 1);
195
196                /* We don't call print_page() here but use scrolling to ensure
197                   faster screen update. However, 'end_reached' and
198                   'page_length' should still be updated, and 'page' should
199                   point to start of next page. This is done by calling
200                   get_line() in the following 'for' loop. */
201                scrollok(text, TRUE);
202                wscrl(text, -1);    /* Scroll text region down one line */
203                scrollok(text, FALSE);
204                page_length = 0;
205                passed_end = 0;
206                for (i = 0; i < height - 4; i++) {
207                    if (!i) {
208                        /* print first line of page */
209                        print_line(text, 0, width - 2);
210                        wnoutrefresh(text);
211                    } else
212                        /* Called to update 'end_reached' and 'page' */
213                        get_line();
214                    if (!passed_end)
215                        page_length++;
216                    if (end_reached && !passed_end)
217                        passed_end = 1;
218                }
219
220                print_position(dialog, height, width);
221                wmove(dialog, cur_y, cur_x);    /* Restore cursor position */
222                wrefresh(dialog);
223            }
224            break;
225        case 'B':   /* Previous page */
226        case 'b':
227        case KEY_PPAGE:
228            if (begin_reached)
229                break;
230            back_lines(page_length + height - 4);
231            print_page(text, height - 4, width - 2);
232            print_position(dialog, height, width);
233            wmove(dialog, cur_y, cur_x);
234            wrefresh(dialog);
235            break;
236        case 'J':   /* Next line */
237        case 'j':
238        case KEY_DOWN:
239            if (!end_reached) {
240                begin_reached = 0;
241                scrollok(text, TRUE);
242                scroll(text);   /* Scroll text region up one line */
243                scrollok(text, FALSE);
244                print_line(text, height - 5, width - 2);
245                wnoutrefresh(text);
246                print_position(dialog, height, width);
247                wmove(dialog, cur_y, cur_x);    /* Restore cursor position */
248                wrefresh(dialog);
249            }
250            break;
251        case KEY_NPAGE: /* Next page */
252        case ' ':
253            if (end_reached)
254                break;
255
256            begin_reached = 0;
257            print_page(text, height - 4, width - 2);
258            print_position(dialog, height, width);
259            wmove(dialog, cur_y, cur_x);
260            wrefresh(dialog);
261            break;
262        case '0':   /* Beginning of line */
263        case 'H':   /* Scroll left */
264        case 'h':
265        case KEY_LEFT:
266            if (hscroll <= 0)
267                break;
268
269            if (key == '0')
270                hscroll = 0;
271            else
272                hscroll--;
273            /* Reprint current page to scroll horizontally */
274            back_lines(page_length);
275            print_page(text, height - 4, width - 2);
276            wmove(dialog, cur_y, cur_x);
277            wrefresh(dialog);
278            break;
279        case 'L':   /* Scroll right */
280        case 'l':
281        case KEY_RIGHT:
282            if (hscroll >= MAX_LEN)
283                break;
284            hscroll++;
285            /* Reprint current page to scroll horizontally */
286            back_lines(page_length);
287            print_page(text, height - 4, width - 2);
288            wmove(dialog, cur_y, cur_x);
289            wrefresh(dialog);
290            break;
291        case ESC:
292            break;
293        }
294    }
295
296    delwin(dialog);
297    free(buf);
298    close(fd);
299    return -1;      /* ESC pressed */
300}
301
302/*
303 * Go back 'n' lines in text file. Called by dialog_textbox().
304 * 'page' will be updated to point to the desired line in 'buf'.
305 */
306static void back_lines(int n)
307{
308    int i, fpos;
309
310    begin_reached = 0;
311    /* We have to distinguish between end_reached and !end_reached
312       since at end of file, the line is not ended by a '\n'.
313       The code inside 'if' basically does a '--page' to move one
314       character backward so as to skip '\n' of the previous line */
315    if (!end_reached) {
316        /* Either beginning of buffer or beginning of file reached? */
317        if (page == buf) {
318            if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) {
319                endwin();
320                fprintf(stderr, "\nError moving file pointer in "
321                            "back_lines().\n");
322                exit(-1);
323            }
324            if (fpos > bytes_read) {    /* Not beginning of file yet */
325                /* We've reached beginning of buffer, but not beginning of
326                   file yet, so read previous part of file into buffer.
327                   Note that we only move backward for BUF_SIZE/2 bytes,
328                   but not BUF_SIZE bytes to avoid re-reading again in
329                   print_page() later */
330                /* Really possible to move backward BUF_SIZE/2 bytes? */
331                if (fpos < BUF_SIZE / 2 + bytes_read) {
332                    /* No, move less then */
333                    if (lseek(fd, 0, SEEK_SET) == -1) {
334                        endwin();
335                        fprintf(stderr, "\nError moving file pointer in "
336                                        "back_lines().\n");
337                        exit(-1);
338                    }
339                    page = buf + fpos - bytes_read;
340                } else {    /* Move backward BUF_SIZE/2 bytes */
341                    if (lseek (fd, -(BUF_SIZE / 2 + bytes_read), SEEK_CUR) == -1) {
342                        endwin();
343                        fprintf(stderr, "\nError moving file pointer "
344                                        "in back_lines().\n");
345                        exit(-1);
346                    }
347                    page = buf + BUF_SIZE / 2;
348                }
349                if ((bytes_read =
350                     read(fd, buf, BUF_SIZE)) == -1) {
351                    endwin();
352                    fprintf(stderr, "\nError reading file in back_lines().\n");
353                    exit(-1);
354                }
355                buf[bytes_read] = '\0';
356            } else {    /* Beginning of file reached */
357                begin_reached = 1;
358                return;
359            }
360        }
361        if (*(--page) != '\n') {    /* '--page' here */
362            /* Something's wrong... */
363            endwin();
364            fprintf(stderr, "\nInternal error in back_lines().\n");
365            exit(-1);
366        }
367    }
368    /* Go back 'n' lines */
369    for (i = 0; i < n; i++)
370        do {
371            if (page == buf) {
372                if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) {
373                    endwin();
374                    fprintf(stderr, "\nError moving file pointer in back_lines().\n");
375                    exit(-1);
376                }
377                if (fpos > bytes_read) {
378                    /* Really possible to move backward BUF_SIZE/2 bytes? */
379                    if (fpos < BUF_SIZE / 2 + bytes_read) {
380                        /* No, move less then */
381                        if (lseek(fd, 0, SEEK_SET) == -1) {
382                            endwin();
383                            fprintf(stderr, "\nError moving file pointer "
384                                            "in back_lines().\n");
385                            exit(-1);
386                        }
387                        page = buf + fpos - bytes_read;
388                    } else {    /* Move backward BUF_SIZE/2 bytes */
389                        if (lseek (fd, -(BUF_SIZE / 2 + bytes_read), SEEK_CUR) == -1) {
390                            endwin();
391                            fprintf(stderr, "\nError moving file pointer"
392                                            " in back_lines().\n");
393                            exit(-1);
394                        }
395                        page = buf + BUF_SIZE / 2;
396                    }
397                    if ((bytes_read =
398                         read(fd, buf, BUF_SIZE)) == -1) {
399                        endwin();
400                        fprintf(stderr, "\nError reading file in "
401                                        "back_lines().\n");
402                        exit(-1);
403                    }
404                    buf[bytes_read] = '\0';
405                } else {    /* Beginning of file reached */
406                    begin_reached = 1;
407                    return;
408                }
409            }
410        } while (*(--page) != '\n');
411    page++;
412}
413
414/*
415 * Print a new page of text. Called by dialog_textbox().
416 */
417static void print_page(WINDOW * win, int height, int width)
418{
419    int i, passed_end = 0;
420
421    page_length = 0;
422    for (i = 0; i < height; i++) {
423        print_line(win, i, width);
424        if (!passed_end)
425            page_length++;
426        if (end_reached && !passed_end)
427            passed_end = 1;
428    }
429    wnoutrefresh(win);
430}
431
432/*
433 * Print a new line of text. Called by dialog_textbox() and print_page().
434 */
435static void print_line(WINDOW * win, int row, int width)
436{
437    char *line;
438
439    line = get_line();
440    line += MIN(strlen(line), hscroll); /* Scroll horizontally */
441    wmove(win, row, 0); /* move cursor to correct line */
442    waddch(win, ' ');
443    waddnstr(win, line, MIN(strlen(line), width - 2));
444
445    /* Clear 'residue' of previous line */
446#if OLD_NCURSES
447    {
448        int i;
449        int y, x;
450
451        getyx(win, y, x);
452        for (i = 0; i < width - x; i++)
453            waddch(win, ' ');
454    }
455#else
456    wclrtoeol(win);
457#endif
458}
459
460/*
461 * Return current line of text. Called by dialog_textbox() and print_line().
462 * 'page' should point to start of current line before calling, and will be
463 * updated to point to start of next line.
464 */
465static char *get_line(void)
466{
467    int i = 0, fpos;
468    static char line[MAX_LEN + 1];
469
470    end_reached = 0;
471    while (*page != '\n') {
472        if (*page == '\0') {
473            /* Either end of file or end of buffer reached */
474            if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) {
475                endwin();
476                fprintf(stderr, "\nError moving file pointer in "
477                                "get_line().\n");
478                exit(-1);
479            }
480            if (fpos < file_size) { /* Not end of file yet */
481                /* We've reached end of buffer, but not end of file yet,
482                   so read next part of file into buffer */
483                if ((bytes_read =
484                     read(fd, buf, BUF_SIZE)) == -1) {
485                    endwin();
486                    fprintf(stderr, "\nError reading file in get_line().\n");
487                    exit(-1);
488                }
489                buf[bytes_read] = '\0';
490                page = buf;
491            } else {
492                if (!end_reached)
493                    end_reached = 1;
494                break;
495            }
496        } else if (i < MAX_LEN)
497            line[i++] = *(page++);
498        else {
499            /* Truncate lines longer than MAX_LEN characters */
500            if (i == MAX_LEN)
501                line[i++] = '\0';
502            page++;
503        }
504    }
505    if (i <= MAX_LEN)
506        line[i] = '\0';
507    if (!end_reached)
508        page++;     /* move pass '\n' */
509
510    return line;
511}
512
513/*
514 * Print current position
515 */
516static void print_position(WINDOW * win, int height, int width)
517{
518    int fpos, percent;
519
520    if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) {
521        endwin();
522        fprintf(stderr, "\nError moving file pointer in print_position().\n");
523        exit(-1);
524    }
525    wattrset(win, position_indicator_attr);
526    wbkgdset(win, position_indicator_attr & A_COLOR);
527    percent = !file_size ?
528        100 : ((fpos - bytes_read + page - buf) * 100) / file_size;
529    wmove(win, height - 3, width - 9);
530    wprintw(win, "(%3d%%)", percent);
531}
Note: See TracBrowser for help on using the repository browser.