• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-WNDR4500v2-V1.0.0.60_1.0.38/src/router/busybox-1.x/scripts/kconfig/lxdialog/
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