source: debwrt/trunk/config/mconf/lxdialog/textbox.c @ 1

Last change on this file since 1 was 1, checked in by amain, 13 years ago

Initial import of the build environment for DebWrt

File size: 14.6 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        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}
Note: See TracBrowser for help on using the repository browser.