Root/scripts/config/lxdialog/textbox.c

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

Archive Download this file



interactive