source: MondoRescue/branches/stable/mindi-busybox/scripts/config/lxdialog/textbox.c @ 821

Last change on this file since 821 was 821, checked in by Bruno Cornec, 14 years ago

Addition of busybox 1.2.1 as a mindi-busybox new package
This should avoid delivering binary files in mindi not built there (Fedora and Debian are quite serious about that)

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