textbox.c revision 224014
1217309Snwhitehorn/*
2224014Snwhitehorn *  $Id: textbox.c,v 1.101 2011/06/29 09:53:03 tom Exp $
3217309Snwhitehorn *
4220749Snwhitehorn *  textbox.c -- implements the text box
5217309Snwhitehorn *
6220749Snwhitehorn *  Copyright 2000-2010,2011	Thomas E.  Dickey
7217309Snwhitehorn *
8217309Snwhitehorn *  This program is free software; you can redistribute it and/or modify
9217309Snwhitehorn *  it under the terms of the GNU Lesser General Public License, version 2.1
10217309Snwhitehorn *  as published by the Free Software Foundation.
11217309Snwhitehorn *
12217309Snwhitehorn *  This program is distributed in the hope that it will be useful, but
13217309Snwhitehorn *  WITHOUT ANY WARRANTY; without even the implied warranty of
14217309Snwhitehorn *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15217309Snwhitehorn *  Lesser General Public License for more details.
16217309Snwhitehorn *
17217309Snwhitehorn *  You should have received a copy of the GNU Lesser General Public
18217309Snwhitehorn *  License along with this program; if not, write to
19217309Snwhitehorn *	Free Software Foundation, Inc.
20217309Snwhitehorn *	51 Franklin St., Fifth Floor
21217309Snwhitehorn *	Boston, MA 02110, USA.
22217309Snwhitehorn *
23217309Snwhitehorn *  An earlier version of this program lists as authors:
24217309Snwhitehorn *	Savio Lam (lam836@cs.cuhk.hk)
25217309Snwhitehorn */
26217309Snwhitehorn
27217309Snwhitehorn#include <dialog.h>
28217309Snwhitehorn#include <dlg_keys.h>
29217309Snwhitehorn
30217309Snwhitehorn#define PAGE_LENGTH	(height - 4)
31217309Snwhitehorn#define PAGE_WIDTH	(width - 2)
32217309Snwhitehorn
33217309Snwhitehorntypedef struct {
34217309Snwhitehorn    DIALOG_CALLBACK obj;
35217309Snwhitehorn    WINDOW *text;
36217309Snwhitehorn    const char **buttons;
37217309Snwhitehorn    int hscroll;
38217309Snwhitehorn    char line[MAX_LEN + 1];
39217309Snwhitehorn    int fd;
40217309Snwhitehorn    long file_size;
41217309Snwhitehorn    long fd_bytes_read;
42217309Snwhitehorn    long bytes_read;
43217309Snwhitehorn    long buffer_len;
44217309Snwhitehorn    bool begin_reached;
45217309Snwhitehorn    bool buffer_first;
46217309Snwhitehorn    bool end_reached;
47217309Snwhitehorn    long page_length;		/* lines on the page which is shown */
48217309Snwhitehorn    long in_buf;		/* ending index into buf[] for page */
49217309Snwhitehorn    char *buf;
50217309Snwhitehorn} MY_OBJ;
51217309Snwhitehorn
52217309Snwhitehornstatic long
53217309Snwhitehornlseek_obj(MY_OBJ * obj, long offset, int mode)
54217309Snwhitehorn{
55217309Snwhitehorn    long fpos;
56217309Snwhitehorn    if ((fpos = (long) lseek(obj->fd, (off_t) offset, mode)) == -1) {
57217309Snwhitehorn	switch (mode) {
58217309Snwhitehorn	case SEEK_CUR:
59217309Snwhitehorn	    dlg_exiterr("Cannot get file position");
60217309Snwhitehorn	    break;
61217309Snwhitehorn	case SEEK_END:
62217309Snwhitehorn	    dlg_exiterr("Cannot seek to end of file");
63217309Snwhitehorn	    break;
64217309Snwhitehorn	case SEEK_SET:
65217309Snwhitehorn	    dlg_exiterr("Cannot set file position to %ld", offset);
66217309Snwhitehorn	    break;
67217309Snwhitehorn	}
68217309Snwhitehorn    }
69217309Snwhitehorn    return fpos;
70217309Snwhitehorn}
71217309Snwhitehorn
72217309Snwhitehornstatic long
73217309Snwhitehornftell_obj(MY_OBJ * obj)
74217309Snwhitehorn{
75220749Snwhitehorn    return lseek_obj(obj, 0L, SEEK_CUR);
76217309Snwhitehorn}
77217309Snwhitehorn
78217309Snwhitehornstatic char *
79217309Snwhitehornxalloc(size_t size)
80217309Snwhitehorn{
81217309Snwhitehorn    char *result = dlg_malloc(char, size);
82217309Snwhitehorn    assert_ptr(result, "xalloc");
83217309Snwhitehorn    return result;
84217309Snwhitehorn}
85217309Snwhitehorn
86217309Snwhitehorn/*
87217309Snwhitehorn * read_high() substitutes read() for tab->spaces conversion
88217309Snwhitehorn *
89217309Snwhitehorn * buffer_len, fd_bytes_read, bytes_read are modified
90217309Snwhitehorn * buf is allocated
91217309Snwhitehorn *
92217309Snwhitehorn * fd_bytes_read is the effective number of bytes read from file
93217309Snwhitehorn * bytes_read is the length of buf, that can be different if tab_correct
94217309Snwhitehorn */
95217309Snwhitehornstatic void
96217309Snwhitehornread_high(MY_OBJ * obj, size_t size_read)
97217309Snwhitehorn{
98217309Snwhitehorn    char *buftab, ch;
99217309Snwhitehorn    int i = 0, j, n, tmpint;
100217309Snwhitehorn    long begin_line;
101217309Snwhitehorn
102217309Snwhitehorn    /* Allocate space for read buffer */
103217309Snwhitehorn    buftab = xalloc(size_read + 1);
104217309Snwhitehorn
105217309Snwhitehorn    if ((obj->fd_bytes_read = read(obj->fd, buftab, size_read)) != -1) {
106217309Snwhitehorn
107217309Snwhitehorn	buftab[obj->fd_bytes_read] = '\0';	/* mark end of valid data */
108217309Snwhitehorn
109217309Snwhitehorn	if (dialog_vars.tab_correct) {
110217309Snwhitehorn
111217309Snwhitehorn	    /* calculate bytes_read by buftab and fd_bytes_read */
112217309Snwhitehorn	    obj->bytes_read = begin_line = 0;
113217309Snwhitehorn	    for (j = 0; j < obj->fd_bytes_read; j++)
114217309Snwhitehorn		if (buftab[j] == TAB)
115217309Snwhitehorn		    obj->bytes_read += dialog_state.tab_len
116217309Snwhitehorn			- ((obj->bytes_read - begin_line)
117217309Snwhitehorn			   % dialog_state.tab_len);
118217309Snwhitehorn		else if (buftab[j] == '\n') {
119217309Snwhitehorn		    obj->bytes_read++;
120217309Snwhitehorn		    begin_line = obj->bytes_read;
121217309Snwhitehorn		} else
122217309Snwhitehorn		    obj->bytes_read++;
123217309Snwhitehorn
124217309Snwhitehorn	    if (obj->bytes_read > obj->buffer_len) {
125217309Snwhitehorn		if (obj->buffer_first)
126217309Snwhitehorn		    obj->buffer_first = FALSE;	/* disp = 0 */
127217309Snwhitehorn		else {
128217309Snwhitehorn		    free(obj->buf);
129217309Snwhitehorn		}
130217309Snwhitehorn
131217309Snwhitehorn		obj->buffer_len = obj->bytes_read;
132217309Snwhitehorn
133217309Snwhitehorn		/* Allocate space for read buffer */
134217309Snwhitehorn		obj->buf = xalloc((size_t) obj->buffer_len + 1);
135217309Snwhitehorn	    }
136217309Snwhitehorn
137217309Snwhitehorn	} else {
138217309Snwhitehorn	    if (obj->buffer_first) {
139217309Snwhitehorn		obj->buffer_first = FALSE;
140217309Snwhitehorn
141217309Snwhitehorn		/* Allocate space for read buffer */
142217309Snwhitehorn		obj->buf = xalloc(size_read + 1);
143217309Snwhitehorn	    }
144217309Snwhitehorn
145217309Snwhitehorn	    obj->bytes_read = obj->fd_bytes_read;
146217309Snwhitehorn	}
147217309Snwhitehorn
148217309Snwhitehorn	j = 0;
149217309Snwhitehorn	begin_line = 0;
150217309Snwhitehorn	while (j < obj->fd_bytes_read)
151217309Snwhitehorn	    if (((ch = buftab[j++]) == TAB) && (dialog_vars.tab_correct != 0)) {
152217309Snwhitehorn		tmpint = (dialog_state.tab_len
153217309Snwhitehorn			  - ((int) ((long) i - begin_line) % dialog_state.tab_len));
154217309Snwhitehorn		for (n = 0; n < tmpint; n++)
155217309Snwhitehorn		    obj->buf[i++] = ' ';
156217309Snwhitehorn	    } else {
157217309Snwhitehorn		if (ch == '\n')
158217309Snwhitehorn		    begin_line = i + 1;
159217309Snwhitehorn		obj->buf[i++] = ch;
160217309Snwhitehorn	    }
161217309Snwhitehorn
162217309Snwhitehorn	obj->buf[i] = '\0';	/* mark end of valid data */
163217309Snwhitehorn
164217309Snwhitehorn    }
165217309Snwhitehorn    if (obj->bytes_read == -1)
166217309Snwhitehorn	dlg_exiterr("Error reading file");
167217309Snwhitehorn    free(buftab);
168217309Snwhitehorn}
169217309Snwhitehorn
170217309Snwhitehornstatic long
171217309Snwhitehornfind_first(MY_OBJ * obj, char *buffer, long length)
172217309Snwhitehorn{
173217309Snwhitehorn    long recount = obj->page_length;
174217309Snwhitehorn    long result = 0;
175217309Snwhitehorn
176217309Snwhitehorn    while (length > 0) {
177217309Snwhitehorn	if (buffer[length] == '\n') {
178217309Snwhitehorn	    if (--recount < 0) {
179217309Snwhitehorn		result = length;
180217309Snwhitehorn		break;
181217309Snwhitehorn	    }
182217309Snwhitehorn	}
183217309Snwhitehorn	--length;
184217309Snwhitehorn    }
185217309Snwhitehorn    return result;
186217309Snwhitehorn}
187217309Snwhitehorn
188217309Snwhitehornstatic long
189217309Snwhitehorntabize(MY_OBJ * obj, long val, long *first_pos)
190217309Snwhitehorn{
191217309Snwhitehorn    long fpos;
192217309Snwhitehorn    long i, count, begin_line;
193217309Snwhitehorn    char *buftab;
194217309Snwhitehorn
195217309Snwhitehorn    if (!dialog_vars.tab_correct)
196217309Snwhitehorn	return val;
197217309Snwhitehorn
198217309Snwhitehorn    fpos = ftell_obj(obj);
199217309Snwhitehorn
200217309Snwhitehorn    lseek_obj(obj, fpos - obj->fd_bytes_read, SEEK_SET);
201217309Snwhitehorn
202217309Snwhitehorn    /* Allocate space for read buffer */
203217309Snwhitehorn    buftab = xalloc((size_t) val + 1);
204217309Snwhitehorn
205217309Snwhitehorn    if ((read(obj->fd, buftab, (size_t) val)) == -1)
206217309Snwhitehorn	dlg_exiterr("Error reading file in tabize().");
207217309Snwhitehorn
208217309Snwhitehorn    begin_line = count = 0;
209217309Snwhitehorn    if (first_pos != 0)
210217309Snwhitehorn	*first_pos = 0;
211217309Snwhitehorn
212217309Snwhitehorn    for (i = 0; i < val; i++) {
213217309Snwhitehorn	if ((first_pos != 0) && (count >= val)) {
214217309Snwhitehorn	    *first_pos = find_first(obj, buftab, i);
215217309Snwhitehorn	    break;
216217309Snwhitehorn	}
217217309Snwhitehorn	if (buftab[i] == TAB)
218217309Snwhitehorn	    count += dialog_state.tab_len
219217309Snwhitehorn		- ((count - begin_line) % dialog_state.tab_len);
220217309Snwhitehorn	else if (buftab[i] == '\n') {
221217309Snwhitehorn	    count++;
222217309Snwhitehorn	    begin_line = count;
223217309Snwhitehorn	} else
224217309Snwhitehorn	    count++;
225217309Snwhitehorn    }
226217309Snwhitehorn
227217309Snwhitehorn    lseek_obj(obj, fpos, SEEK_SET);
228217309Snwhitehorn    free(buftab);
229217309Snwhitehorn    return count;
230217309Snwhitehorn}
231217309Snwhitehorn/*
232217309Snwhitehorn * Return current line of text.
233217309Snwhitehorn * 'page' should point to start of current line before calling, and will be
234217309Snwhitehorn * updated to point to start of next line.
235217309Snwhitehorn */
236217309Snwhitehornstatic char *
237217309Snwhitehornget_line(MY_OBJ * obj)
238217309Snwhitehorn{
239217309Snwhitehorn    int i = 0;
240217309Snwhitehorn    long fpos;
241217309Snwhitehorn
242217309Snwhitehorn    obj->end_reached = FALSE;
243217309Snwhitehorn    while (obj->buf[obj->in_buf] != '\n') {
244217309Snwhitehorn	if (obj->buf[obj->in_buf] == '\0') {	/* Either end of file or end of buffer reached */
245217309Snwhitehorn	    fpos = ftell_obj(obj);
246217309Snwhitehorn
247217309Snwhitehorn	    if (fpos < obj->file_size) {	/* Not end of file yet */
248217309Snwhitehorn		/* We've reached end of buffer, but not end of file yet, so
249217309Snwhitehorn		 * read next part of file into buffer
250217309Snwhitehorn		 */
251217309Snwhitehorn		read_high(obj, BUF_SIZE);
252217309Snwhitehorn		obj->in_buf = 0;
253217309Snwhitehorn	    } else {
254217309Snwhitehorn		if (!obj->end_reached)
255217309Snwhitehorn		    obj->end_reached = TRUE;
256217309Snwhitehorn		break;
257217309Snwhitehorn	    }
258217309Snwhitehorn	} else if (i < MAX_LEN)
259217309Snwhitehorn	    obj->line[i++] = obj->buf[obj->in_buf++];
260217309Snwhitehorn	else {
261217309Snwhitehorn	    if (i == MAX_LEN)	/* Truncate lines longer than MAX_LEN characters */
262217309Snwhitehorn		obj->line[i++] = '\0';
263217309Snwhitehorn	    obj->in_buf++;
264217309Snwhitehorn	}
265217309Snwhitehorn    }
266217309Snwhitehorn    if (i <= MAX_LEN)
267217309Snwhitehorn	obj->line[i] = '\0';
268217309Snwhitehorn    if (!obj->end_reached)
269217309Snwhitehorn	obj->in_buf++;		/* move past '\n' */
270217309Snwhitehorn
271217309Snwhitehorn    return obj->line;
272217309Snwhitehorn}
273217309Snwhitehorn
274217309Snwhitehornstatic bool
275217309Snwhitehornmatch_string(MY_OBJ * obj, char *string)
276217309Snwhitehorn{
277217309Snwhitehorn    char *match = get_line(obj);
278217309Snwhitehorn    return strstr(match, string) != 0;
279217309Snwhitehorn}
280217309Snwhitehorn
281217309Snwhitehorn/*
282217309Snwhitehorn * Go back 'n' lines in text file. Called by dialog_textbox().
283217309Snwhitehorn * 'in_buf' will be updated to point to the desired line in 'buf'.
284217309Snwhitehorn */
285217309Snwhitehornstatic void
286217309Snwhitehornback_lines(MY_OBJ * obj, long n)
287217309Snwhitehorn{
288217309Snwhitehorn    int i;
289217309Snwhitehorn    long fpos;
290217309Snwhitehorn    long val_to_tabize;
291217309Snwhitehorn
292217309Snwhitehorn    obj->begin_reached = FALSE;
293217309Snwhitehorn    /* We have to distinguish between end_reached and !end_reached since at end
294217309Snwhitehorn       * of file, the line is not ended by a '\n'.  The code inside 'if'
295217309Snwhitehorn       * basically does a '--in_buf' to move one character backward so as to
296217309Snwhitehorn       * skip '\n' of the previous line */
297217309Snwhitehorn    if (!obj->end_reached) {
298217309Snwhitehorn	/* Either beginning of buffer or beginning of file reached? */
299217309Snwhitehorn
300217309Snwhitehorn	if (obj->in_buf == 0) {
301217309Snwhitehorn	    fpos = ftell_obj(obj);
302217309Snwhitehorn
303217309Snwhitehorn	    if (fpos > obj->fd_bytes_read) {	/* Not beginning of file yet */
304217309Snwhitehorn		/* We've reached beginning of buffer, but not beginning of file
305217309Snwhitehorn		 * yet, so read previous part of file into buffer.  Note that
306217309Snwhitehorn		 * we only move backward for BUF_SIZE/2 bytes, but not BUF_SIZE
307217309Snwhitehorn		 * bytes to avoid re-reading again in print_page() later
308217309Snwhitehorn		 */
309217309Snwhitehorn		/* Really possible to move backward BUF_SIZE/2 bytes? */
310217309Snwhitehorn		if (fpos < BUF_SIZE / 2 + obj->fd_bytes_read) {
311217309Snwhitehorn		    /* No, move less than */
312220749Snwhitehorn		    lseek_obj(obj, 0L, SEEK_SET);
313217309Snwhitehorn		    val_to_tabize = fpos - obj->fd_bytes_read;
314217309Snwhitehorn		} else {	/* Move backward BUF_SIZE/2 bytes */
315217309Snwhitehorn		    lseek_obj(obj, -(BUF_SIZE / 2 + obj->fd_bytes_read), SEEK_CUR);
316217309Snwhitehorn		    val_to_tabize = BUF_SIZE / 2;
317217309Snwhitehorn		}
318217309Snwhitehorn		read_high(obj, BUF_SIZE);
319217309Snwhitehorn
320217309Snwhitehorn		obj->in_buf = tabize(obj, val_to_tabize, (long *) 0);
321217309Snwhitehorn
322217309Snwhitehorn	    } else {		/* Beginning of file reached */
323217309Snwhitehorn		obj->begin_reached = TRUE;
324217309Snwhitehorn		return;
325217309Snwhitehorn	    }
326217309Snwhitehorn	}
327217309Snwhitehorn	obj->in_buf--;
328217309Snwhitehorn	if (obj->buf[obj->in_buf] != '\n')
329217309Snwhitehorn	    /* Something's wrong... */
330217309Snwhitehorn	    dlg_exiterr("Internal error in back_lines().");
331217309Snwhitehorn    }
332217309Snwhitehorn
333217309Snwhitehorn    /* Go back 'n' lines */
334217309Snwhitehorn    for (i = 0; i < n; i++) {
335217309Snwhitehorn	do {
336217309Snwhitehorn	    if (obj->in_buf == 0) {
337217309Snwhitehorn		fpos = ftell_obj(obj);
338217309Snwhitehorn
339217309Snwhitehorn		if (fpos > obj->fd_bytes_read) {
340217309Snwhitehorn		    /* Really possible to move backward BUF_SIZE/2 bytes? */
341217309Snwhitehorn		    if (fpos < BUF_SIZE / 2 + obj->fd_bytes_read) {
342217309Snwhitehorn			/* No, move less than */
343220749Snwhitehorn			lseek_obj(obj, 0L, SEEK_SET);
344217309Snwhitehorn			val_to_tabize = fpos - obj->fd_bytes_read;
345217309Snwhitehorn		    } else {	/* Move backward BUF_SIZE/2 bytes */
346217309Snwhitehorn			lseek_obj(obj, -(BUF_SIZE / 2 + obj->fd_bytes_read), SEEK_CUR);
347217309Snwhitehorn			val_to_tabize = BUF_SIZE / 2;
348217309Snwhitehorn		    }
349217309Snwhitehorn		    read_high(obj, BUF_SIZE);
350217309Snwhitehorn
351217309Snwhitehorn		    obj->in_buf = tabize(obj, val_to_tabize, (long *) 0);
352217309Snwhitehorn
353217309Snwhitehorn		} else {	/* Beginning of file reached */
354217309Snwhitehorn		    obj->begin_reached = TRUE;
355217309Snwhitehorn		    return;
356217309Snwhitehorn		}
357217309Snwhitehorn	    }
358217309Snwhitehorn	} while (obj->buf[--(obj->in_buf)] != '\n');
359217309Snwhitehorn    }
360217309Snwhitehorn    obj->in_buf++;
361217309Snwhitehorn}
362217309Snwhitehorn
363217309Snwhitehorn/*
364217309Snwhitehorn * Print a new line of text.
365217309Snwhitehorn */
366217309Snwhitehornstatic void
367217309Snwhitehornprint_line(MY_OBJ * obj, int row, int width)
368217309Snwhitehorn{
369217309Snwhitehorn    if (wmove(obj->text, row, 0) != ERR) {
370217309Snwhitehorn	int i, y, x;
371217309Snwhitehorn	char *line = get_line(obj);
372217309Snwhitehorn	const int *cols = dlg_index_columns(line);
373217309Snwhitehorn	const int *indx = dlg_index_wchars(line);
374217309Snwhitehorn	int limit = dlg_count_wchars(line);
375217309Snwhitehorn	int first = 0;
376217309Snwhitehorn	int last = limit;
377217309Snwhitehorn
378217309Snwhitehorn	if (width > getmaxx(obj->text))
379217309Snwhitehorn	    width = getmaxx(obj->text);
380217309Snwhitehorn	--width;		/* for the leading ' ' */
381217309Snwhitehorn
382217309Snwhitehorn	for (i = 0; i <= limit && cols[i] < obj->hscroll; ++i)
383217309Snwhitehorn	    first = i;
384217309Snwhitehorn
385217309Snwhitehorn	for (i = first; (i <= limit) && ((cols[i] - cols[first]) < width); ++i)
386217309Snwhitehorn	    last = i;
387217309Snwhitehorn
388217309Snwhitehorn	(void) waddch(obj->text, ' ');
389217309Snwhitehorn	(void) waddnstr(obj->text, line + indx[first], indx[last] - indx[first]);
390217309Snwhitehorn
391217309Snwhitehorn	getyx(obj->text, y, x);
392217309Snwhitehorn	if (y == row) {		/* Clear 'residue' of previous line */
393217309Snwhitehorn	    for (i = 0; i <= width - x; i++) {
394217309Snwhitehorn		(void) waddch(obj->text, ' ');
395217309Snwhitehorn	    }
396217309Snwhitehorn	}
397217309Snwhitehorn    }
398217309Snwhitehorn}
399217309Snwhitehorn
400217309Snwhitehorn/*
401217309Snwhitehorn * Print a new page of text.
402217309Snwhitehorn */
403217309Snwhitehornstatic void
404217309Snwhitehornprint_page(MY_OBJ * obj, int height, int width)
405217309Snwhitehorn{
406217309Snwhitehorn    int i, passed_end = 0;
407217309Snwhitehorn
408217309Snwhitehorn    obj->page_length = 0;
409217309Snwhitehorn    for (i = 0; i < height; i++) {
410217309Snwhitehorn	print_line(obj, i, width);
411217309Snwhitehorn	if (!passed_end)
412217309Snwhitehorn	    obj->page_length++;
413217309Snwhitehorn	if (obj->end_reached && !passed_end)
414217309Snwhitehorn	    passed_end = 1;
415217309Snwhitehorn    }
416217309Snwhitehorn    (void) wnoutrefresh(obj->text);
417217309Snwhitehorn}
418217309Snwhitehorn
419217309Snwhitehorn/*
420217309Snwhitehorn * Print current position
421217309Snwhitehorn */
422217309Snwhitehornstatic void
423217309Snwhitehornprint_position(MY_OBJ * obj, WINDOW *win, int height, int width)
424217309Snwhitehorn{
425217309Snwhitehorn    long fpos;
426217309Snwhitehorn    long size;
427217309Snwhitehorn    long first = -1;
428217309Snwhitehorn
429217309Snwhitehorn    fpos = ftell_obj(obj);
430217309Snwhitehorn    if (dialog_vars.tab_correct)
431217309Snwhitehorn	size = tabize(obj, obj->in_buf, &first);
432217309Snwhitehorn    else
433217309Snwhitehorn	first = find_first(obj, obj->buf, size = obj->in_buf);
434217309Snwhitehorn
435217309Snwhitehorn    dlg_draw_scrollbar(win,
436217309Snwhitehorn		       first,
437217309Snwhitehorn		       fpos - obj->fd_bytes_read + size,
438217309Snwhitehorn		       fpos - obj->fd_bytes_read + size,
439217309Snwhitehorn		       obj->file_size,
440217309Snwhitehorn		       0, PAGE_WIDTH,
441217309Snwhitehorn		       0, PAGE_LENGTH + 1,
442217309Snwhitehorn		       border_attr,
443217309Snwhitehorn		       border_attr);
444217309Snwhitehorn}
445217309Snwhitehorn
446217309Snwhitehorn/*
447217309Snwhitehorn * Display a dialog box and get the search term from user.
448217309Snwhitehorn */
449217309Snwhitehornstatic int
450217309Snwhitehornget_search_term(WINDOW *dialog, char *input, int height, int width)
451217309Snwhitehorn{
452217309Snwhitehorn    /* *INDENT-OFF* */
453217309Snwhitehorn    static DLG_KEYS_BINDING binding[] = {
454217309Snwhitehorn	INPUTSTR_BINDINGS,
455224014Snwhitehorn	HELPKEY_BINDINGS,
456217309Snwhitehorn	ENTERKEY_BINDINGS,
457217309Snwhitehorn	END_KEYS_BINDING
458217309Snwhitehorn    };
459217309Snwhitehorn    /* *INDENT-ON* */
460217309Snwhitehorn
461217309Snwhitehorn    int old_x, old_y;
462217309Snwhitehorn    int box_x, box_y;
463217309Snwhitehorn    int box_height, box_width;
464217309Snwhitehorn    int offset = 0;
465217309Snwhitehorn    int key = 0;
466217309Snwhitehorn    int fkey = 0;
467217309Snwhitehorn    bool first = TRUE;
468217309Snwhitehorn    int result = DLG_EXIT_UNKNOWN;
469220749Snwhitehorn    const char *caption = _("Search");
470217309Snwhitehorn    int len_caption = dlg_count_columns(caption);
471217309Snwhitehorn    const int *indx;
472217309Snwhitehorn    int limit;
473217309Snwhitehorn    WINDOW *widget;
474217309Snwhitehorn
475217309Snwhitehorn    getbegyx(dialog, old_y, old_x);
476217309Snwhitehorn
477217309Snwhitehorn    box_height = 1 + (2 * MARGIN);
478217309Snwhitehorn    box_width = len_caption + (2 * (MARGIN + 2));
479217309Snwhitehorn    box_width = MAX(box_width, 30);
480217309Snwhitehorn    box_width = MIN(box_width, getmaxx(dialog) - 2 * MARGIN);
481217309Snwhitehorn    len_caption = MIN(len_caption, box_width - (2 * (MARGIN + 1)));
482217309Snwhitehorn
483217309Snwhitehorn    box_x = (width - box_width) / 2;
484217309Snwhitehorn    box_y = (height - box_height) / 2;
485217309Snwhitehorn    widget = dlg_new_modal_window(dialog,
486217309Snwhitehorn				  box_height, box_width,
487217309Snwhitehorn				  old_y + box_y, old_x + box_x);
488217309Snwhitehorn    keypad(widget, TRUE);
489217309Snwhitehorn    dlg_register_window(widget, "searchbox", binding);
490217309Snwhitehorn
491217309Snwhitehorn    dlg_draw_box(widget, 0, 0, box_height, box_width,
492217309Snwhitehorn		 searchbox_attr,
493217309Snwhitehorn		 searchbox_border_attr);
494217309Snwhitehorn    wattrset(widget, searchbox_title_attr);
495217309Snwhitehorn    (void) wmove(widget, 0, (box_width - len_caption) / 2);
496217309Snwhitehorn
497217309Snwhitehorn    indx = dlg_index_wchars(caption);
498217309Snwhitehorn    limit = dlg_limit_columns(caption, len_caption, 0);
499217309Snwhitehorn    (void) waddnstr(widget, caption + indx[0], indx[limit] - indx[0]);
500217309Snwhitehorn
501217309Snwhitehorn    box_y++;
502217309Snwhitehorn    box_x++;
503217309Snwhitehorn    box_width -= 2;
504217309Snwhitehorn    offset = dlg_count_columns(input);
505217309Snwhitehorn
506217309Snwhitehorn    while (result == DLG_EXIT_UNKNOWN) {
507217309Snwhitehorn	if (!first) {
508217309Snwhitehorn	    key = dlg_getc(widget, &fkey);
509217309Snwhitehorn	    if (fkey) {
510217309Snwhitehorn		switch (fkey) {
511217309Snwhitehorn#ifdef KEY_RESIZE
512217309Snwhitehorn		case KEY_RESIZE:
513217309Snwhitehorn		    result = DLG_EXIT_CANCEL;
514217309Snwhitehorn		    continue;
515217309Snwhitehorn#endif
516217309Snwhitehorn		case DLGK_ENTER:
517217309Snwhitehorn		    result = DLG_EXIT_OK;
518217309Snwhitehorn		    continue;
519217309Snwhitehorn		}
520217309Snwhitehorn	    } else if (key == ESC) {
521217309Snwhitehorn		result = DLG_EXIT_ESC;
522217309Snwhitehorn		continue;
523217309Snwhitehorn	    } else if (key == ERR) {
524217309Snwhitehorn		napms(50);
525217309Snwhitehorn		continue;
526217309Snwhitehorn	    }
527217309Snwhitehorn	}
528217309Snwhitehorn	if (dlg_edit_string(input, &offset, key, fkey, first)) {
529217309Snwhitehorn	    dlg_show_string(widget, input, offset, searchbox_attr,
530217309Snwhitehorn			    1, 1, box_width, FALSE, first);
531217309Snwhitehorn	    first = FALSE;
532217309Snwhitehorn	}
533217309Snwhitehorn    }
534217309Snwhitehorn    dlg_del_window(widget);
535217309Snwhitehorn    return result;
536217309Snwhitehorn}
537217309Snwhitehorn
538217309Snwhitehornstatic bool
539217309Snwhitehornperform_search(MY_OBJ * obj, int height, int width, int key, char *search_term)
540217309Snwhitehorn{
541217309Snwhitehorn    int dir;
542217309Snwhitehorn    long tempinx;
543217309Snwhitehorn    long fpos;
544217309Snwhitehorn    int result;
545217309Snwhitehorn    bool found;
546217309Snwhitehorn    bool temp, temp1;
547217309Snwhitehorn    bool moved = FALSE;
548217309Snwhitehorn
549217309Snwhitehorn    /* set search direction */
550217309Snwhitehorn    dir = (key == '/' || key == 'n') ? 1 : 0;
551217309Snwhitehorn    if (dir ? !obj->end_reached : !obj->begin_reached) {
552217309Snwhitehorn	if (key == 'n' || key == 'N') {
553217309Snwhitehorn	    if (search_term[0] == '\0') {	/* No search term yet */
554217309Snwhitehorn		(void) beep();
555217309Snwhitehorn		return FALSE;
556217309Snwhitehorn	    }
557217309Snwhitehorn	    /* Get search term from user */
558217309Snwhitehorn	} else if ((result = get_search_term(obj->text, search_term,
559217309Snwhitehorn					     PAGE_LENGTH,
560217309Snwhitehorn					     PAGE_WIDTH)) != DLG_EXIT_OK
561217309Snwhitehorn		   || search_term[0] == '\0') {
562217309Snwhitehorn#ifdef KEY_RESIZE
563217309Snwhitehorn	    if (result == DLG_EXIT_CANCEL) {
564217309Snwhitehorn		ungetch(key);
565217309Snwhitehorn		ungetch(KEY_RESIZE);
566217309Snwhitehorn		/* FALLTHRU */
567217309Snwhitehorn	    }
568217309Snwhitehorn#endif
569217309Snwhitehorn	    /* ESC pressed, or no search term, reprint page to clear box */
570217309Snwhitehorn	    wattrset(obj->text, dialog_attr);
571217309Snwhitehorn	    back_lines(obj, obj->page_length);
572217309Snwhitehorn	    return TRUE;
573217309Snwhitehorn	}
574217309Snwhitehorn	/* Save variables for restoring in case search term can't be found */
575217309Snwhitehorn	tempinx = obj->in_buf;
576217309Snwhitehorn	temp = obj->begin_reached;
577217309Snwhitehorn	temp1 = obj->end_reached;
578217309Snwhitehorn	fpos = ftell_obj(obj) - obj->fd_bytes_read;
579217309Snwhitehorn	/* update 'in_buf' to point to next (previous) line before
580217309Snwhitehorn	   forward (backward) searching */
581217309Snwhitehorn	back_lines(obj, (dir
582217309Snwhitehorn			 ? obj->page_length - 1
583217309Snwhitehorn			 : obj->page_length + 1));
584217309Snwhitehorn	found = FALSE;
585217309Snwhitehorn	if (dir) {		/* Forward search */
586217309Snwhitehorn	    while ((found = match_string(obj, search_term)) == FALSE) {
587217309Snwhitehorn		if (obj->end_reached)
588217309Snwhitehorn		    break;
589217309Snwhitehorn	    }
590217309Snwhitehorn	} else {		/* Backward search */
591217309Snwhitehorn	    while ((found = match_string(obj, search_term)) == FALSE) {
592217309Snwhitehorn		if (obj->begin_reached)
593217309Snwhitehorn		    break;
594220749Snwhitehorn		back_lines(obj, 2L);
595217309Snwhitehorn	    }
596217309Snwhitehorn	}
597217309Snwhitehorn	if (found == FALSE) {	/* not found */
598217309Snwhitehorn	    (void) beep();
599217309Snwhitehorn	    /* Restore program state to that before searching */
600217309Snwhitehorn	    lseek_obj(obj, fpos, SEEK_SET);
601217309Snwhitehorn
602217309Snwhitehorn	    read_high(obj, BUF_SIZE);
603217309Snwhitehorn
604217309Snwhitehorn	    obj->in_buf = tempinx;
605217309Snwhitehorn	    obj->begin_reached = temp;
606217309Snwhitehorn	    obj->end_reached = temp1;
607217309Snwhitehorn	    /* move 'in_buf' to point to start of current page to
608217309Snwhitehorn	     * re-print current page.  Note that 'in_buf' always points
609217309Snwhitehorn	     * to start of next page, so this is necessary
610217309Snwhitehorn	     */
611217309Snwhitehorn	    back_lines(obj, obj->page_length);
612217309Snwhitehorn	} else {		/* Search term found */
613220749Snwhitehorn	    back_lines(obj, 1L);
614217309Snwhitehorn	}
615217309Snwhitehorn	/* Reprint page */
616217309Snwhitehorn	wattrset(obj->text, dialog_attr);
617217309Snwhitehorn	moved = TRUE;
618217309Snwhitehorn    } else {			/* no need to find */
619217309Snwhitehorn	(void) beep();
620217309Snwhitehorn    }
621217309Snwhitehorn    return moved;
622217309Snwhitehorn}
623217309Snwhitehorn
624217309Snwhitehorn/*
625217309Snwhitehorn * Display text from a file in a dialog box.
626217309Snwhitehorn */
627217309Snwhitehornint
628217309Snwhitehorndialog_textbox(const char *title, const char *file, int height, int width)
629217309Snwhitehorn{
630217309Snwhitehorn    /* *INDENT-OFF* */
631217309Snwhitehorn    static DLG_KEYS_BINDING binding[] = {
632224014Snwhitehorn	HELPKEY_BINDINGS,
633217309Snwhitehorn	ENTERKEY_BINDINGS,
634217309Snwhitehorn	DLG_KEYS_DATA( DLGK_GRID_DOWN,  'J' ),
635217309Snwhitehorn	DLG_KEYS_DATA( DLGK_GRID_DOWN,  'j' ),
636217309Snwhitehorn	DLG_KEYS_DATA( DLGK_GRID_DOWN,  KEY_DOWN ),
637217309Snwhitehorn	DLG_KEYS_DATA( DLGK_GRID_LEFT,  'H' ),
638217309Snwhitehorn	DLG_KEYS_DATA( DLGK_GRID_LEFT,  'h' ),
639217309Snwhitehorn	DLG_KEYS_DATA( DLGK_GRID_LEFT,  KEY_LEFT ),
640217309Snwhitehorn	DLG_KEYS_DATA( DLGK_GRID_RIGHT, 'L' ),
641217309Snwhitehorn	DLG_KEYS_DATA( DLGK_GRID_RIGHT, 'l' ),
642217309Snwhitehorn	DLG_KEYS_DATA( DLGK_GRID_RIGHT, KEY_RIGHT ),
643217309Snwhitehorn	DLG_KEYS_DATA( DLGK_GRID_UP,    'K' ),
644217309Snwhitehorn	DLG_KEYS_DATA( DLGK_GRID_UP,    'k' ),
645217309Snwhitehorn	DLG_KEYS_DATA( DLGK_GRID_UP,    KEY_UP ),
646217309Snwhitehorn	DLG_KEYS_DATA( DLGK_PAGE_FIRST, 'g' ),
647217309Snwhitehorn	DLG_KEYS_DATA( DLGK_PAGE_FIRST, KEY_HOME ),
648217309Snwhitehorn	DLG_KEYS_DATA( DLGK_PAGE_LAST,  'G' ),
649217309Snwhitehorn	DLG_KEYS_DATA( DLGK_PAGE_LAST,  KEY_END ),
650217309Snwhitehorn	DLG_KEYS_DATA( DLGK_PAGE_LAST,  KEY_LL ),
651217309Snwhitehorn	DLG_KEYS_DATA( DLGK_PAGE_NEXT,  ' ' ),
652217309Snwhitehorn	DLG_KEYS_DATA( DLGK_PAGE_NEXT,  KEY_NPAGE ),
653217309Snwhitehorn	DLG_KEYS_DATA( DLGK_PAGE_PREV,  'B' ),
654217309Snwhitehorn	DLG_KEYS_DATA( DLGK_PAGE_PREV,  'b' ),
655217309Snwhitehorn	DLG_KEYS_DATA( DLGK_PAGE_PREV,  KEY_PPAGE ),
656217309Snwhitehorn	DLG_KEYS_DATA( DLGK_BEGIN,	'0' ),
657217309Snwhitehorn	DLG_KEYS_DATA( DLGK_BEGIN,	KEY_BEG ),
658217309Snwhitehorn	DLG_KEYS_DATA( DLGK_FIELD_NEXT, TAB ),
659217309Snwhitehorn	DLG_KEYS_DATA( DLGK_FIELD_PREV, KEY_BTAB ),
660217309Snwhitehorn	END_KEYS_BINDING
661217309Snwhitehorn    };
662217309Snwhitehorn    /* *INDENT-ON* */
663217309Snwhitehorn
664217309Snwhitehorn#ifdef KEY_RESIZE
665217309Snwhitehorn    int old_height = height;
666217309Snwhitehorn    int old_width = width;
667217309Snwhitehorn#endif
668217309Snwhitehorn    long fpos;
669217309Snwhitehorn    int x, y, cur_x, cur_y;
670217309Snwhitehorn    int key = 0, fkey;
671217309Snwhitehorn    int next = 0;
672217309Snwhitehorn    int i, code, passed_end;
673217309Snwhitehorn    char search_term[MAX_LEN + 1];
674217309Snwhitehorn    MY_OBJ obj;
675217309Snwhitehorn    WINDOW *dialog;
676217309Snwhitehorn    bool moved;
677217309Snwhitehorn    int result = DLG_EXIT_UNKNOWN;
678217309Snwhitehorn    int button = dialog_vars.extra_button ? dlg_defaultno_button() : 0;
679217309Snwhitehorn    int min_width = 12;
680217309Snwhitehorn
681217309Snwhitehorn    search_term[0] = '\0';	/* no search term entered yet */
682217309Snwhitehorn
683217309Snwhitehorn    memset(&obj, 0, sizeof(obj));
684217309Snwhitehorn
685217309Snwhitehorn    obj.begin_reached = TRUE;
686217309Snwhitehorn    obj.buffer_first = TRUE;
687217309Snwhitehorn    obj.end_reached = FALSE;
688217309Snwhitehorn    obj.buttons = dlg_exit_label();
689217309Snwhitehorn
690217309Snwhitehorn    /* Open input file for reading */
691217309Snwhitehorn    if ((obj.fd = open(file, O_RDONLY)) == -1)
692217309Snwhitehorn	dlg_exiterr("Can't open input file %s", file);
693217309Snwhitehorn
694217309Snwhitehorn    /* Get file size. Actually, 'file_size' is the real file size - 1,
695217309Snwhitehorn       since it's only the last byte offset from the beginning */
696220749Snwhitehorn    obj.file_size = lseek_obj(&obj, 0L, SEEK_END);
697217309Snwhitehorn
698217309Snwhitehorn    /* Restore file pointer to beginning of file after getting file size */
699220749Snwhitehorn    lseek_obj(&obj, 0L, SEEK_SET);
700217309Snwhitehorn
701217309Snwhitehorn    read_high(&obj, BUF_SIZE);
702217309Snwhitehorn
703217309Snwhitehorn    dlg_button_layout(obj.buttons, &min_width);
704217309Snwhitehorn
705217309Snwhitehorn#ifdef KEY_RESIZE
706217309Snwhitehorn  retry:
707217309Snwhitehorn#endif
708217309Snwhitehorn    moved = TRUE;
709217309Snwhitehorn
710217309Snwhitehorn    dlg_auto_sizefile(title, file, &height, &width, 2, min_width);
711217309Snwhitehorn    dlg_print_size(height, width);
712217309Snwhitehorn    dlg_ctl_size(height, width);
713217309Snwhitehorn
714217309Snwhitehorn    x = dlg_box_x_ordinate(width);
715217309Snwhitehorn    y = dlg_box_y_ordinate(height);
716217309Snwhitehorn
717217309Snwhitehorn    dialog = dlg_new_window(height, width, y, x);
718217309Snwhitehorn    dlg_register_window(dialog, "textbox", binding);
719217309Snwhitehorn    dlg_register_buttons(dialog, "textbox", obj.buttons);
720217309Snwhitehorn
721217309Snwhitehorn    dlg_mouse_setbase(x, y);
722217309Snwhitehorn
723217309Snwhitehorn    /* Create window for text region, used for scrolling text */
724217309Snwhitehorn    obj.text = dlg_sub_window(dialog, PAGE_LENGTH, PAGE_WIDTH, y + 1, x + 1);
725217309Snwhitehorn
726217309Snwhitehorn    /* register the new window, along with its borders */
727217309Snwhitehorn    dlg_mouse_mkbigregion(0, 0, PAGE_LENGTH + 2, width, KEY_MAX, 1, 1, 1 /* lines */ );
728217309Snwhitehorn    dlg_draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr);
729217309Snwhitehorn    dlg_draw_bottom_box(dialog);
730217309Snwhitehorn    dlg_draw_title(dialog, title);
731217309Snwhitehorn
732217309Snwhitehorn    dlg_draw_buttons(dialog, PAGE_LENGTH + 2, 0, obj.buttons, button, FALSE, width);
733217309Snwhitehorn    (void) wnoutrefresh(dialog);
734217309Snwhitehorn    getyx(dialog, cur_y, cur_x);	/* Save cursor position */
735217309Snwhitehorn
736217309Snwhitehorn    dlg_attr_clear(obj.text, PAGE_LENGTH, PAGE_WIDTH, dialog_attr);
737217309Snwhitehorn
738217309Snwhitehorn    while (result == DLG_EXIT_UNKNOWN) {
739217309Snwhitehorn
740217309Snwhitehorn	/*
741217309Snwhitehorn	 * Update the screen according to whether we shifted up/down by a line
742217309Snwhitehorn	 * or not.
743217309Snwhitehorn	 */
744217309Snwhitehorn	if (moved) {
745217309Snwhitehorn	    if (next < 0) {
746217309Snwhitehorn		(void) scrollok(obj.text, TRUE);
747217309Snwhitehorn		(void) scroll(obj.text);	/* Scroll text region up one line */
748217309Snwhitehorn		(void) scrollok(obj.text, FALSE);
749217309Snwhitehorn		print_line(&obj, PAGE_LENGTH - 1, PAGE_WIDTH);
750217309Snwhitehorn		(void) wnoutrefresh(obj.text);
751217309Snwhitehorn	    } else if (next > 0) {
752217309Snwhitehorn		/*
753217309Snwhitehorn		 * We don't call print_page() here but use scrolling to ensure
754217309Snwhitehorn		 * faster screen update.  However, 'end_reached' and
755217309Snwhitehorn		 * 'page_length' should still be updated, and 'in_buf' should
756217309Snwhitehorn		 * point to start of next page.  This is done by calling
757217309Snwhitehorn		 * get_line() in the following 'for' loop.
758217309Snwhitehorn		 */
759217309Snwhitehorn		(void) scrollok(obj.text, TRUE);
760217309Snwhitehorn		(void) wscrl(obj.text, -1);	/* Scroll text region down one line */
761217309Snwhitehorn		(void) scrollok(obj.text, FALSE);
762217309Snwhitehorn		obj.page_length = 0;
763217309Snwhitehorn		passed_end = 0;
764217309Snwhitehorn		for (i = 0; i < PAGE_LENGTH; i++) {
765217309Snwhitehorn		    if (!i) {
766217309Snwhitehorn			print_line(&obj, 0, PAGE_WIDTH);	/* print first line of page */
767217309Snwhitehorn			(void) wnoutrefresh(obj.text);
768217309Snwhitehorn		    } else
769217309Snwhitehorn			(void) get_line(&obj);	/* Called to update 'end_reached' and 'in_buf' */
770217309Snwhitehorn		    if (!passed_end)
771217309Snwhitehorn			obj.page_length++;
772217309Snwhitehorn		    if (obj.end_reached && !passed_end)
773217309Snwhitehorn			passed_end = 1;
774217309Snwhitehorn		}
775217309Snwhitehorn	    } else {
776217309Snwhitehorn		print_page(&obj, PAGE_LENGTH, PAGE_WIDTH);
777217309Snwhitehorn	    }
778217309Snwhitehorn	    print_position(&obj, dialog, height, width);
779217309Snwhitehorn	    (void) wmove(dialog, cur_y, cur_x);		/* Restore cursor position */
780217309Snwhitehorn	    wrefresh(dialog);
781217309Snwhitehorn	}
782217309Snwhitehorn	moved = FALSE;		/* assume we'll not move */
783217309Snwhitehorn	next = 0;		/* ...but not scroll by a line */
784217309Snwhitehorn
785217309Snwhitehorn	key = dlg_mouse_wgetch(dialog, &fkey);
786217309Snwhitehorn	if (dlg_result_key(key, fkey, &result))
787217309Snwhitehorn	    break;
788217309Snwhitehorn
789217309Snwhitehorn	if (!fkey && (code = dlg_char_to_button(key, obj.buttons)) >= 0) {
790217309Snwhitehorn	    result = dlg_ok_buttoncode(code);
791217309Snwhitehorn	    break;
792217309Snwhitehorn	}
793217309Snwhitehorn
794217309Snwhitehorn	if (fkey) {
795217309Snwhitehorn	    switch (key) {
796217309Snwhitehorn	    default:
797217309Snwhitehorn		if (is_DLGK_MOUSE(key)) {
798217309Snwhitehorn		    result = dlg_exit_buttoncode(key - M_EVENT);
799217309Snwhitehorn		    if (result < 0)
800217309Snwhitehorn			result = DLG_EXIT_OK;
801217309Snwhitehorn		} else {
802217309Snwhitehorn		    beep();
803217309Snwhitehorn		}
804217309Snwhitehorn		break;
805217309Snwhitehorn	    case DLGK_FIELD_NEXT:
806217309Snwhitehorn		button = dlg_next_button(obj.buttons, button);
807217309Snwhitehorn		if (button < 0)
808217309Snwhitehorn		    button = 0;
809217309Snwhitehorn		dlg_draw_buttons(dialog,
810217309Snwhitehorn				 height - 2, 0,
811217309Snwhitehorn				 obj.buttons, button,
812217309Snwhitehorn				 FALSE, width);
813217309Snwhitehorn		break;
814217309Snwhitehorn	    case DLGK_FIELD_PREV:
815217309Snwhitehorn		button = dlg_prev_button(obj.buttons, button);
816217309Snwhitehorn		if (button < 0)
817217309Snwhitehorn		    button = 0;
818217309Snwhitehorn		dlg_draw_buttons(dialog,
819217309Snwhitehorn				 height - 2, 0,
820217309Snwhitehorn				 obj.buttons, button,
821217309Snwhitehorn				 FALSE, width);
822217309Snwhitehorn		break;
823217309Snwhitehorn	    case DLGK_ENTER:
824224014Snwhitehorn		if (dialog_vars.nook)
825224014Snwhitehorn		    result = DLG_EXIT_OK;
826224014Snwhitehorn		else
827224014Snwhitehorn		    result = dlg_exit_buttoncode(button);
828217309Snwhitehorn		break;
829217309Snwhitehorn	    case DLGK_PAGE_FIRST:
830217309Snwhitehorn		if (!obj.begin_reached) {
831217309Snwhitehorn		    obj.begin_reached = 1;
832217309Snwhitehorn		    /* First page not in buffer? */
833217309Snwhitehorn		    fpos = ftell_obj(&obj);
834217309Snwhitehorn
835217309Snwhitehorn		    if (fpos > obj.fd_bytes_read) {
836217309Snwhitehorn			/* Yes, we have to read it in */
837220749Snwhitehorn			lseek_obj(&obj, 0L, SEEK_SET);
838217309Snwhitehorn
839217309Snwhitehorn			read_high(&obj, BUF_SIZE);
840217309Snwhitehorn		    }
841217309Snwhitehorn		    obj.in_buf = 0;
842217309Snwhitehorn		    moved = TRUE;
843217309Snwhitehorn		}
844217309Snwhitehorn		break;
845217309Snwhitehorn	    case DLGK_PAGE_LAST:
846217309Snwhitehorn		obj.end_reached = TRUE;
847217309Snwhitehorn		/* Last page not in buffer? */
848217309Snwhitehorn		fpos = ftell_obj(&obj);
849217309Snwhitehorn
850217309Snwhitehorn		if (fpos < obj.file_size) {
851217309Snwhitehorn		    /* Yes, we have to read it in */
852217309Snwhitehorn		    lseek_obj(&obj, -BUF_SIZE, SEEK_END);
853217309Snwhitehorn
854217309Snwhitehorn		    read_high(&obj, BUF_SIZE);
855217309Snwhitehorn		}
856217309Snwhitehorn		obj.in_buf = obj.bytes_read;
857220749Snwhitehorn		back_lines(&obj, (long) PAGE_LENGTH);
858217309Snwhitehorn		moved = TRUE;
859217309Snwhitehorn		break;
860217309Snwhitehorn	    case DLGK_GRID_UP:	/* Previous line */
861217309Snwhitehorn		if (!obj.begin_reached) {
862217309Snwhitehorn		    back_lines(&obj, obj.page_length + 1);
863217309Snwhitehorn		    next = 1;
864217309Snwhitehorn		    moved = TRUE;
865217309Snwhitehorn		}
866217309Snwhitehorn		break;
867217309Snwhitehorn	    case DLGK_PAGE_PREV:	/* Previous page */
868217309Snwhitehorn	    case DLGK_MOUSE(KEY_PPAGE):
869217309Snwhitehorn		if (!obj.begin_reached) {
870217309Snwhitehorn		    back_lines(&obj, obj.page_length + PAGE_LENGTH);
871217309Snwhitehorn		    moved = TRUE;
872217309Snwhitehorn		}
873217309Snwhitehorn		break;
874217309Snwhitehorn	    case DLGK_GRID_DOWN:	/* Next line */
875217309Snwhitehorn		if (!obj.end_reached) {
876217309Snwhitehorn		    obj.begin_reached = 0;
877217309Snwhitehorn		    next = -1;
878217309Snwhitehorn		    moved = TRUE;
879217309Snwhitehorn		}
880217309Snwhitehorn		break;
881217309Snwhitehorn	    case DLGK_PAGE_NEXT:	/* Next page */
882217309Snwhitehorn	    case DLGK_MOUSE(KEY_NPAGE):
883217309Snwhitehorn		if (!obj.end_reached) {
884217309Snwhitehorn		    obj.begin_reached = 0;
885217309Snwhitehorn		    moved = TRUE;
886217309Snwhitehorn		}
887217309Snwhitehorn		break;
888217309Snwhitehorn	    case DLGK_BEGIN:	/* Beginning of line */
889217309Snwhitehorn		if (obj.hscroll > 0) {
890217309Snwhitehorn		    obj.hscroll = 0;
891217309Snwhitehorn		    /* Reprint current page to scroll horizontally */
892217309Snwhitehorn		    back_lines(&obj, obj.page_length);
893217309Snwhitehorn		    moved = TRUE;
894217309Snwhitehorn		}
895217309Snwhitehorn		break;
896217309Snwhitehorn	    case DLGK_GRID_LEFT:	/* Scroll left */
897217309Snwhitehorn		if (obj.hscroll > 0) {
898217309Snwhitehorn		    obj.hscroll--;
899217309Snwhitehorn		    /* Reprint current page to scroll horizontally */
900217309Snwhitehorn		    back_lines(&obj, obj.page_length);
901217309Snwhitehorn		    moved = TRUE;
902217309Snwhitehorn		}
903217309Snwhitehorn		break;
904217309Snwhitehorn	    case DLGK_GRID_RIGHT:	/* Scroll right */
905217309Snwhitehorn		if (obj.hscroll < MAX_LEN) {
906217309Snwhitehorn		    obj.hscroll++;
907217309Snwhitehorn		    /* Reprint current page to scroll horizontally */
908217309Snwhitehorn		    back_lines(&obj, obj.page_length);
909217309Snwhitehorn		    moved = TRUE;
910217309Snwhitehorn		}
911217309Snwhitehorn		break;
912217309Snwhitehorn#ifdef KEY_RESIZE
913217309Snwhitehorn	    case KEY_RESIZE:
914217309Snwhitehorn		/* reset data */
915217309Snwhitehorn		height = old_height;
916217309Snwhitehorn		width = old_width;
917217309Snwhitehorn		back_lines(&obj, obj.page_length);
918217309Snwhitehorn		moved = TRUE;
919217309Snwhitehorn		/* repaint */
920217309Snwhitehorn		dlg_clear();
921217309Snwhitehorn		dlg_del_window(dialog);
922217309Snwhitehorn		refresh();
923217309Snwhitehorn		dlg_mouse_free_regions();
924217309Snwhitehorn		goto retry;
925217309Snwhitehorn#endif
926217309Snwhitehorn	    }
927217309Snwhitehorn	} else {
928217309Snwhitehorn	    switch (key) {
929217309Snwhitehorn	    case '/':		/* Forward search */
930217309Snwhitehorn	    case 'n':		/* Repeat forward search */
931217309Snwhitehorn	    case '?':		/* Backward search */
932217309Snwhitehorn	    case 'N':		/* Repeat backward search */
933217309Snwhitehorn		moved = perform_search(&obj, height, width, key, search_term);
934217309Snwhitehorn		fkey = FALSE;
935217309Snwhitehorn		break;
936217309Snwhitehorn	    default:
937217309Snwhitehorn		beep();
938217309Snwhitehorn		break;
939217309Snwhitehorn	    }
940217309Snwhitehorn	}
941217309Snwhitehorn    }
942217309Snwhitehorn
943217309Snwhitehorn    dlg_del_window(dialog);
944217309Snwhitehorn    free(obj.buf);
945217309Snwhitehorn    (void) close(obj.fd);
946217309Snwhitehorn    dlg_mouse_free_regions();
947217309Snwhitehorn    return result;
948217309Snwhitehorn}
949