xref: /dflybsd-src/contrib/dialog/textbox.c (revision b2dabe2e739bd72461a68ac543307c2dedfb048c)
15382d832SPeter Avalos /*
2*a8e38dc0SAntonio Huete Jimenez  *  $Id: textbox.c,v 1.128 2022/04/03 22:38:16 tom Exp $
35382d832SPeter Avalos  *
45382d832SPeter Avalos  *  textbox.c -- implements the text box
55382d832SPeter Avalos  *
6*a8e38dc0SAntonio Huete Jimenez  *  Copyright 2000-2021,2022	Thomas E. Dickey
75382d832SPeter Avalos  *
85382d832SPeter Avalos  *  This program is free software; you can redistribute it and/or modify
95382d832SPeter Avalos  *  it under the terms of the GNU Lesser General Public License, version 2.1
105382d832SPeter Avalos  *  as published by the Free Software Foundation.
115382d832SPeter Avalos  *
125382d832SPeter Avalos  *  This program is distributed in the hope that it will be useful, but
135382d832SPeter Avalos  *  WITHOUT ANY WARRANTY; without even the implied warranty of
145382d832SPeter Avalos  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
155382d832SPeter Avalos  *  Lesser General Public License for more details.
165382d832SPeter Avalos  *
175382d832SPeter Avalos  *  You should have received a copy of the GNU Lesser General Public
185382d832SPeter Avalos  *  License along with this program; if not, write to
195382d832SPeter Avalos  *	Free Software Foundation, Inc.
205382d832SPeter Avalos  *	51 Franklin St., Fifth Floor
215382d832SPeter Avalos  *	Boston, MA 02110, USA.
225382d832SPeter Avalos  *
235382d832SPeter Avalos  *  An earlier version of this program lists as authors:
245382d832SPeter Avalos  *	Savio Lam (lam836@cs.cuhk.hk)
255382d832SPeter Avalos  */
265382d832SPeter Avalos 
27*a8e38dc0SAntonio Huete Jimenez #include <dlg_internals.h>
285382d832SPeter Avalos #include <dlg_keys.h>
295382d832SPeter Avalos 
305382d832SPeter Avalos #define PAGE_LENGTH	(height - 4)
315382d832SPeter Avalos #define PAGE_WIDTH	(width - 2)
325382d832SPeter Avalos 
335382d832SPeter Avalos typedef struct {
345382d832SPeter Avalos     DIALOG_CALLBACK obj;
355382d832SPeter Avalos     WINDOW *text;
365382d832SPeter Avalos     const char **buttons;
375382d832SPeter Avalos     int hscroll;
385382d832SPeter Avalos     char line[MAX_LEN + 1];
395382d832SPeter Avalos     int fd;
405382d832SPeter Avalos     long file_size;
415382d832SPeter Avalos     long fd_bytes_read;
425382d832SPeter Avalos     long bytes_read;
435382d832SPeter Avalos     long buffer_len;
445382d832SPeter Avalos     bool begin_reached;
455382d832SPeter Avalos     bool buffer_first;
465382d832SPeter Avalos     bool end_reached;
475382d832SPeter Avalos     long page_length;		/* lines on the page which is shown */
485382d832SPeter Avalos     long in_buf;		/* ending index into buf[] for page */
495382d832SPeter Avalos     char *buf;
505382d832SPeter Avalos } MY_OBJ;
515382d832SPeter Avalos 
525382d832SPeter Avalos static long
lseek_obj(MY_OBJ * obj,long offset,int mode)535382d832SPeter Avalos lseek_obj(MY_OBJ * obj, long offset, int mode)
545382d832SPeter Avalos {
555382d832SPeter Avalos     long fpos;
565382d832SPeter Avalos     if ((fpos = (long) lseek(obj->fd, (off_t) offset, mode)) == -1) {
575382d832SPeter Avalos 	switch (mode) {
585382d832SPeter Avalos 	default:
595382d832SPeter Avalos 	case SEEK_CUR:
605382d832SPeter Avalos 	    dlg_exiterr("Cannot get file position");
615382d832SPeter Avalos 	    break;
625382d832SPeter Avalos 	case SEEK_END:
635382d832SPeter Avalos 	    dlg_exiterr("Cannot seek to end of file");
645382d832SPeter Avalos 	    break;
655382d832SPeter Avalos 	case SEEK_SET:
665382d832SPeter Avalos 	    dlg_exiterr("Cannot set file position to %ld", offset);
675382d832SPeter Avalos 	    break;
685382d832SPeter Avalos 	}
695382d832SPeter Avalos     }
705382d832SPeter Avalos     return fpos;
715382d832SPeter Avalos }
725382d832SPeter Avalos 
735382d832SPeter Avalos static long
ftell_obj(MY_OBJ * obj)745382d832SPeter Avalos ftell_obj(MY_OBJ * obj)
755382d832SPeter Avalos {
765382d832SPeter Avalos     return lseek_obj(obj, 0L, SEEK_CUR);
775382d832SPeter Avalos }
785382d832SPeter Avalos 
795382d832SPeter Avalos static void
lseek_set(MY_OBJ * obj,long offset)805382d832SPeter Avalos lseek_set(MY_OBJ * obj, long offset)
815382d832SPeter Avalos {
825382d832SPeter Avalos     long actual = lseek_obj(obj, offset, SEEK_SET);
835382d832SPeter Avalos 
845382d832SPeter Avalos     if (actual != offset) {
855382d832SPeter Avalos 	dlg_exiterr("Cannot set file position to %ld (actual %ld)\n",
865382d832SPeter Avalos 		    offset, actual);
875382d832SPeter Avalos     }
885382d832SPeter Avalos }
895382d832SPeter Avalos 
905382d832SPeter Avalos static void
lseek_end(MY_OBJ * obj,long offset)915382d832SPeter Avalos lseek_end(MY_OBJ * obj, long offset)
925382d832SPeter Avalos {
935382d832SPeter Avalos     long actual = lseek_obj(obj, offset, SEEK_END);
945382d832SPeter Avalos 
955940c9abSDaniel Fojt     if (offset == 0L && actual > offset) {
965382d832SPeter Avalos 	obj->file_size = actual;
975382d832SPeter Avalos     }
985382d832SPeter Avalos }
995382d832SPeter Avalos 
1005382d832SPeter Avalos static void
lseek_cur(MY_OBJ * obj,long offset)1015382d832SPeter Avalos lseek_cur(MY_OBJ * obj, long offset)
1025382d832SPeter Avalos {
1035382d832SPeter Avalos     long actual = lseek_obj(obj, offset, SEEK_CUR);
1045382d832SPeter Avalos 
1055382d832SPeter Avalos     if (actual != offset) {
1065940c9abSDaniel Fojt 	DLG_TRACE(("# Lseek returned %ld, expected %ld\n", actual, offset));
1075382d832SPeter Avalos     }
1085382d832SPeter Avalos }
1095382d832SPeter Avalos 
1105382d832SPeter Avalos static char *
xalloc(size_t size)1115382d832SPeter Avalos xalloc(size_t size)
1125382d832SPeter Avalos {
1135382d832SPeter Avalos     char *result = dlg_malloc(char, size);
1145382d832SPeter Avalos     assert_ptr(result, "xalloc");
1155382d832SPeter Avalos     return result;
1165382d832SPeter Avalos }
1175382d832SPeter Avalos 
1185382d832SPeter Avalos /*
1195382d832SPeter Avalos  * read_high() substitutes read() for tab->spaces conversion
1205382d832SPeter Avalos  *
1215382d832SPeter Avalos  * buffer_len, fd_bytes_read, bytes_read are modified
1225382d832SPeter Avalos  * buf is allocated
1235382d832SPeter Avalos  *
1245382d832SPeter Avalos  * fd_bytes_read is the effective number of bytes read from file
1255382d832SPeter Avalos  * bytes_read is the length of buf, that can be different if tab_correct
1265382d832SPeter Avalos  */
1275382d832SPeter Avalos static void
read_high(MY_OBJ * obj,size_t size_read)1285382d832SPeter Avalos read_high(MY_OBJ * obj, size_t size_read)
1295382d832SPeter Avalos {
1305940c9abSDaniel Fojt     char *buftab;
1315382d832SPeter Avalos 
1325382d832SPeter Avalos     /* Allocate space for read buffer */
1335382d832SPeter Avalos     buftab = xalloc(size_read + 1);
1345382d832SPeter Avalos 
1355382d832SPeter Avalos     if ((obj->fd_bytes_read = read(obj->fd, buftab, size_read)) != -1) {
136*a8e38dc0SAntonio Huete Jimenez 	int j;
1375940c9abSDaniel Fojt 	long begin_line;
1385382d832SPeter Avalos 
1395382d832SPeter Avalos 	buftab[obj->fd_bytes_read] = '\0';	/* mark end of valid data */
1405382d832SPeter Avalos 
1415382d832SPeter Avalos 	if (dialog_vars.tab_correct) {
1425382d832SPeter Avalos 
1435382d832SPeter Avalos 	    /* calculate bytes_read by buftab and fd_bytes_read */
1445382d832SPeter Avalos 	    obj->bytes_read = begin_line = 0;
1455382d832SPeter Avalos 	    for (j = 0; j < obj->fd_bytes_read; j++)
1465382d832SPeter Avalos 		if (buftab[j] == TAB)
1475382d832SPeter Avalos 		    obj->bytes_read += dialog_state.tab_len
1485382d832SPeter Avalos 			- ((obj->bytes_read - begin_line)
1495382d832SPeter Avalos 			   % dialog_state.tab_len);
1505382d832SPeter Avalos 		else if (buftab[j] == '\n') {
1515382d832SPeter Avalos 		    obj->bytes_read++;
1525382d832SPeter Avalos 		    begin_line = obj->bytes_read;
1535382d832SPeter Avalos 		} else
1545382d832SPeter Avalos 		    obj->bytes_read++;
1555382d832SPeter Avalos 
1565382d832SPeter Avalos 	    if (obj->bytes_read > obj->buffer_len) {
1575382d832SPeter Avalos 		if (obj->buffer_first)
1585382d832SPeter Avalos 		    obj->buffer_first = FALSE;	/* disp = 0 */
1595382d832SPeter Avalos 		else {
1605382d832SPeter Avalos 		    free(obj->buf);
1615382d832SPeter Avalos 		}
1625382d832SPeter Avalos 
1635382d832SPeter Avalos 		obj->buffer_len = obj->bytes_read;
1645382d832SPeter Avalos 
1655382d832SPeter Avalos 		/* Allocate space for read buffer */
1665382d832SPeter Avalos 		obj->buf = xalloc((size_t) obj->buffer_len + 1);
1675382d832SPeter Avalos 	    }
1685382d832SPeter Avalos 
1695382d832SPeter Avalos 	} else {
1705382d832SPeter Avalos 	    if (obj->buffer_first) {
1715382d832SPeter Avalos 		obj->buffer_first = FALSE;
1725382d832SPeter Avalos 
1735382d832SPeter Avalos 		/* Allocate space for read buffer */
1745382d832SPeter Avalos 		obj->buf = xalloc(size_read + 1);
1755382d832SPeter Avalos 	    }
1765382d832SPeter Avalos 
1775382d832SPeter Avalos 	    obj->bytes_read = obj->fd_bytes_read;
1785382d832SPeter Avalos 	}
1795382d832SPeter Avalos 
1805382d832SPeter Avalos 	j = 0;
1815382d832SPeter Avalos 	begin_line = 0;
182*a8e38dc0SAntonio Huete Jimenez 	if (obj->buf != NULL) {
183*a8e38dc0SAntonio Huete Jimenez 	    int i = 0;
184*a8e38dc0SAntonio Huete Jimenez 
1855940c9abSDaniel Fojt 	    while (j < obj->fd_bytes_read) {
1865940c9abSDaniel Fojt 		char ch;
1875940c9abSDaniel Fojt 
188*a8e38dc0SAntonio Huete Jimenez 		if (((ch = buftab[j++]) == TAB)
189*a8e38dc0SAntonio Huete Jimenez 		    && (dialog_vars.tab_correct != 0)) {
190*a8e38dc0SAntonio Huete Jimenez 		    int n;
191*a8e38dc0SAntonio Huete Jimenez 		    int tmpint = (dialog_state.tab_len
1925382d832SPeter Avalos 				  - ((int) ((long) i - begin_line) % dialog_state.tab_len));
1935382d832SPeter Avalos 		    for (n = 0; n < tmpint; n++)
1945382d832SPeter Avalos 			obj->buf[i++] = ' ';
1955382d832SPeter Avalos 		} else {
1965382d832SPeter Avalos 		    if (ch == '\n')
1975382d832SPeter Avalos 			begin_line = i + 1;
1985382d832SPeter Avalos 		    obj->buf[i++] = ch;
1995382d832SPeter Avalos 		}
2005940c9abSDaniel Fojt 	    }
2015382d832SPeter Avalos 
2025382d832SPeter Avalos 	    obj->buf[i] = '\0';	/* mark end of valid data */
203*a8e38dc0SAntonio Huete Jimenez 	}
2045382d832SPeter Avalos 
2055382d832SPeter Avalos     }
2065382d832SPeter Avalos     if (obj->bytes_read == -1)
2075382d832SPeter Avalos 	dlg_exiterr("Error reading file");
2085382d832SPeter Avalos     free(buftab);
2095382d832SPeter Avalos }
2105382d832SPeter Avalos 
2115382d832SPeter Avalos static long
find_first(MY_OBJ * obj,char * buffer,long length)2125382d832SPeter Avalos find_first(MY_OBJ * obj, char *buffer, long length)
2135382d832SPeter Avalos {
2145382d832SPeter Avalos     long result = 0;
2155382d832SPeter Avalos 
216*a8e38dc0SAntonio Huete Jimenez     if (buffer != NULL) {
217*a8e38dc0SAntonio Huete Jimenez 	long recount = obj->page_length;
2185382d832SPeter Avalos 	while (length > 0) {
2195382d832SPeter Avalos 	    if (buffer[length] == '\n') {
2205382d832SPeter Avalos 		if (--recount < 0) {
2215382d832SPeter Avalos 		    result = length;
2225382d832SPeter Avalos 		    break;
2235382d832SPeter Avalos 		}
2245382d832SPeter Avalos 	    }
2255382d832SPeter Avalos 	    --length;
2265382d832SPeter Avalos 	}
227*a8e38dc0SAntonio Huete Jimenez     }
2285382d832SPeter Avalos     return result;
2295382d832SPeter Avalos }
2305382d832SPeter Avalos 
2315382d832SPeter Avalos static long
tabize(MY_OBJ * obj,long val,long * first_pos)2325382d832SPeter Avalos tabize(MY_OBJ * obj, long val, long *first_pos)
2335382d832SPeter Avalos {
2345382d832SPeter Avalos     long fpos;
2355382d832SPeter Avalos     long i, count, begin_line;
2365382d832SPeter Avalos     char *buftab;
2375382d832SPeter Avalos 
2385382d832SPeter Avalos     if (!dialog_vars.tab_correct)
2395382d832SPeter Avalos 	return val;
2405382d832SPeter Avalos 
2415382d832SPeter Avalos     fpos = ftell_obj(obj);
2425382d832SPeter Avalos 
2435382d832SPeter Avalos     lseek_set(obj, fpos - obj->fd_bytes_read);
2445382d832SPeter Avalos 
2455382d832SPeter Avalos     /* Allocate space for read buffer */
2465382d832SPeter Avalos     buftab = xalloc((size_t) val + 1);
2475382d832SPeter Avalos 
2485382d832SPeter Avalos     if ((read(obj->fd, buftab, (size_t) val)) == -1)
2495382d832SPeter Avalos 	dlg_exiterr("Error reading file in tabize().");
2505382d832SPeter Avalos 
2515382d832SPeter Avalos     begin_line = count = 0;
2525382d832SPeter Avalos     if (first_pos != 0)
2535382d832SPeter Avalos 	*first_pos = 0;
2545382d832SPeter Avalos 
2555382d832SPeter Avalos     for (i = 0; i < val; i++) {
2565382d832SPeter Avalos 	if ((first_pos != 0) && (count >= val)) {
2575382d832SPeter Avalos 	    *first_pos = find_first(obj, buftab, i);
2585382d832SPeter Avalos 	    break;
2595382d832SPeter Avalos 	}
2605382d832SPeter Avalos 	if (buftab[i] == TAB)
2615382d832SPeter Avalos 	    count += dialog_state.tab_len
2625382d832SPeter Avalos 		- ((count - begin_line) % dialog_state.tab_len);
2635382d832SPeter Avalos 	else if (buftab[i] == '\n') {
2645382d832SPeter Avalos 	    count++;
2655382d832SPeter Avalos 	    begin_line = count;
2665382d832SPeter Avalos 	} else
2675382d832SPeter Avalos 	    count++;
2685382d832SPeter Avalos     }
2695382d832SPeter Avalos 
2705382d832SPeter Avalos     lseek_set(obj, fpos);
2715382d832SPeter Avalos     free(buftab);
2725382d832SPeter Avalos     return count;
2735382d832SPeter Avalos }
2745382d832SPeter Avalos /*
2755382d832SPeter Avalos  * Return current line of text.
2765382d832SPeter Avalos  * 'page' should point to start of current line before calling, and will be
2775382d832SPeter Avalos  * updated to point to start of next line.
2785382d832SPeter Avalos  */
2795382d832SPeter Avalos static char *
get_line(MY_OBJ * obj)2805382d832SPeter Avalos get_line(MY_OBJ * obj)
2815382d832SPeter Avalos {
2825382d832SPeter Avalos     int i = 0;
2835382d832SPeter Avalos 
2845382d832SPeter Avalos     obj->end_reached = FALSE;
285*a8e38dc0SAntonio Huete Jimenez     if (obj->buf != NULL) {
2865382d832SPeter Avalos 	while (obj->buf[obj->in_buf] != '\n') {
2875382d832SPeter Avalos 	    if (obj->buf[obj->in_buf] == '\0') {	/* Either end of file or end of buffer reached */
288*a8e38dc0SAntonio Huete Jimenez 		long fpos = ftell_obj(obj);
2895382d832SPeter Avalos 
2905382d832SPeter Avalos 		if (fpos < obj->file_size) {	/* Not end of file yet */
2915382d832SPeter Avalos 		    /* We've reached end of buffer, but not end of file yet, so
2925382d832SPeter Avalos 		     * read next part of file into buffer
2935382d832SPeter Avalos 		     */
2945382d832SPeter Avalos 		    read_high(obj, BUF_SIZE);
2955382d832SPeter Avalos 		    obj->in_buf = 0;
2965382d832SPeter Avalos 		} else {
2975382d832SPeter Avalos 		    if (!obj->end_reached)
2985382d832SPeter Avalos 			obj->end_reached = TRUE;
2995382d832SPeter Avalos 		    break;
3005382d832SPeter Avalos 		}
3015382d832SPeter Avalos 	    } else if (i < MAX_LEN)
3025382d832SPeter Avalos 		obj->line[i++] = obj->buf[obj->in_buf++];
3035382d832SPeter Avalos 	    else {
3045382d832SPeter Avalos 		if (i == MAX_LEN)	/* Truncate lines longer than MAX_LEN characters */
3055382d832SPeter Avalos 		    obj->line[i++] = '\0';
3065382d832SPeter Avalos 		obj->in_buf++;
3075382d832SPeter Avalos 	    }
3085382d832SPeter Avalos 	}
309*a8e38dc0SAntonio Huete Jimenez     }
3105382d832SPeter Avalos     if (i <= MAX_LEN)
3115382d832SPeter Avalos 	obj->line[i] = '\0';
3125382d832SPeter Avalos     if (!obj->end_reached)
3135382d832SPeter Avalos 	obj->in_buf++;		/* move past '\n' */
3145382d832SPeter Avalos 
3155382d832SPeter Avalos     return obj->line;
3165382d832SPeter Avalos }
3175382d832SPeter Avalos 
3185382d832SPeter Avalos static bool
match_string(MY_OBJ * obj,char * string)3195382d832SPeter Avalos match_string(MY_OBJ * obj, char *string)
3205382d832SPeter Avalos {
3215382d832SPeter Avalos     char *match = get_line(obj);
3225382d832SPeter Avalos     return strstr(match, string) != 0;
3235382d832SPeter Avalos }
3245382d832SPeter Avalos 
3255382d832SPeter Avalos /*
3265382d832SPeter Avalos  * Go back 'n' lines in text file. Called by dialog_textbox().
3275382d832SPeter Avalos  * 'in_buf' will be updated to point to the desired line in 'buf'.
3285382d832SPeter Avalos  */
3295382d832SPeter Avalos static void
back_lines(MY_OBJ * obj,long n)3305382d832SPeter Avalos back_lines(MY_OBJ * obj, long n)
3315382d832SPeter Avalos {
3325382d832SPeter Avalos     int i;
3335382d832SPeter Avalos     long fpos;
3345382d832SPeter Avalos     long val_to_tabize;
3355382d832SPeter Avalos 
3365382d832SPeter Avalos     obj->begin_reached = FALSE;
3375382d832SPeter Avalos     /* We have to distinguish between end_reached and !end_reached since at end
3385382d832SPeter Avalos        * of file, the line is not ended by a '\n'.  The code inside 'if'
3395382d832SPeter Avalos        * basically does a '--in_buf' to move one character backward so as to
3405382d832SPeter Avalos        * skip '\n' of the previous line */
3415382d832SPeter Avalos     if (!obj->end_reached) {
3425382d832SPeter Avalos 	/* Either beginning of buffer or beginning of file reached? */
3435382d832SPeter Avalos 
3445382d832SPeter Avalos 	if (obj->in_buf == 0) {
3455382d832SPeter Avalos 	    fpos = ftell_obj(obj);
3465382d832SPeter Avalos 
3475382d832SPeter Avalos 	    if (fpos > obj->fd_bytes_read) {	/* Not beginning of file yet */
3485382d832SPeter Avalos 		/* We've reached beginning of buffer, but not beginning of file
3495382d832SPeter Avalos 		 * yet, so read previous part of file into buffer.  Note that
3505382d832SPeter Avalos 		 * we only move backward for BUF_SIZE/2 bytes, but not BUF_SIZE
3515382d832SPeter Avalos 		 * bytes to avoid re-reading again in print_page() later
3525382d832SPeter Avalos 		 */
3535382d832SPeter Avalos 		/* Really possible to move backward BUF_SIZE/2 bytes? */
3545382d832SPeter Avalos 		if (fpos < BUF_SIZE / 2 + obj->fd_bytes_read) {
3555382d832SPeter Avalos 		    /* No, move less than */
3565382d832SPeter Avalos 		    lseek_set(obj, 0L);
3575382d832SPeter Avalos 		    val_to_tabize = fpos - obj->fd_bytes_read;
3585382d832SPeter Avalos 		} else {	/* Move backward BUF_SIZE/2 bytes */
3595382d832SPeter Avalos 		    lseek_cur(obj, -(BUF_SIZE / 2 + obj->fd_bytes_read));
3605382d832SPeter Avalos 		    val_to_tabize = BUF_SIZE / 2;
3615382d832SPeter Avalos 		}
3625382d832SPeter Avalos 		read_high(obj, BUF_SIZE);
3635382d832SPeter Avalos 
3645382d832SPeter Avalos 		obj->in_buf = tabize(obj, val_to_tabize, (long *) 0);
3655382d832SPeter Avalos 
3665382d832SPeter Avalos 	    } else {		/* Beginning of file reached */
3675382d832SPeter Avalos 		obj->begin_reached = TRUE;
3685382d832SPeter Avalos 		return;
3695382d832SPeter Avalos 	    }
3705382d832SPeter Avalos 	}
3715382d832SPeter Avalos 	obj->in_buf--;
372*a8e38dc0SAntonio Huete Jimenez 	if (obj->buf == NULL
373*a8e38dc0SAntonio Huete Jimenez 	    || obj->in_buf < 0
374*a8e38dc0SAntonio Huete Jimenez 	    || obj->in_buf >= obj->bytes_read
375*a8e38dc0SAntonio Huete Jimenez 	    || obj->buf[obj->in_buf] != '\n')
3765382d832SPeter Avalos 	    /* Something's wrong... */
3775382d832SPeter Avalos 	    dlg_exiterr("Internal error in back_lines().");
3785382d832SPeter Avalos     }
3795382d832SPeter Avalos 
3805382d832SPeter Avalos     /* Go back 'n' lines */
3815382d832SPeter Avalos     for (i = 0; i < n; i++) {
3825382d832SPeter Avalos 	do {
3835382d832SPeter Avalos 	    if (obj->in_buf == 0) {
3845382d832SPeter Avalos 		fpos = ftell_obj(obj);
3855382d832SPeter Avalos 
3865382d832SPeter Avalos 		if (fpos > obj->fd_bytes_read) {
3875382d832SPeter Avalos 		    /* Really possible to move backward BUF_SIZE/2 bytes? */
3885382d832SPeter Avalos 		    if (fpos < BUF_SIZE / 2 + obj->fd_bytes_read) {
3895382d832SPeter Avalos 			/* No, move less than */
3905382d832SPeter Avalos 			lseek_set(obj, 0L);
3915382d832SPeter Avalos 			val_to_tabize = fpos - obj->fd_bytes_read;
3925382d832SPeter Avalos 		    } else {	/* Move backward BUF_SIZE/2 bytes */
3935382d832SPeter Avalos 			lseek_cur(obj, -(BUF_SIZE / 2 + obj->fd_bytes_read));
3945382d832SPeter Avalos 			val_to_tabize = BUF_SIZE / 2;
3955382d832SPeter Avalos 		    }
3965382d832SPeter Avalos 		    read_high(obj, BUF_SIZE);
3975382d832SPeter Avalos 
3985382d832SPeter Avalos 		    obj->in_buf = tabize(obj, val_to_tabize, (long *) 0);
3995382d832SPeter Avalos 
4005382d832SPeter Avalos 		} else {	/* Beginning of file reached */
4015382d832SPeter Avalos 		    obj->begin_reached = TRUE;
4025382d832SPeter Avalos 		    return;
4035382d832SPeter Avalos 		}
4045382d832SPeter Avalos 	    }
4055382d832SPeter Avalos 	} while (obj->buf[--(obj->in_buf)] != '\n');
4065382d832SPeter Avalos     }
4075382d832SPeter Avalos     obj->in_buf++;
4085382d832SPeter Avalos }
4095382d832SPeter Avalos 
4105382d832SPeter Avalos /*
4115382d832SPeter Avalos  * Print a new line of text.
4125382d832SPeter Avalos  */
4135382d832SPeter Avalos static void
print_line(MY_OBJ * obj,int row,int width)4145382d832SPeter Avalos print_line(MY_OBJ * obj, int row, int width)
4155382d832SPeter Avalos {
4165382d832SPeter Avalos     if (wmove(obj->text, row, 0) != ERR) {
4175382d832SPeter Avalos 	int i, y, x;
4185382d832SPeter Avalos 	char *line = get_line(obj);
4195382d832SPeter Avalos 	const int *cols = dlg_index_columns(line);
4205382d832SPeter Avalos 	const int *indx = dlg_index_wchars(line);
4215382d832SPeter Avalos 	int limit = dlg_count_wchars(line);
4225382d832SPeter Avalos 	int first = 0;
4235382d832SPeter Avalos 	int last = limit;
4245382d832SPeter Avalos 
4255382d832SPeter Avalos 	if (width > getmaxx(obj->text))
4265382d832SPeter Avalos 	    width = getmaxx(obj->text);
4275382d832SPeter Avalos 	--width;		/* for the leading ' ' */
4285382d832SPeter Avalos 
4295382d832SPeter Avalos 	for (i = 0; i <= limit && cols[i] < obj->hscroll; ++i)
4305382d832SPeter Avalos 	    first = i;
4315382d832SPeter Avalos 
4325382d832SPeter Avalos 	for (i = first; (i <= limit) && ((cols[i] - cols[first]) < width); ++i)
4335382d832SPeter Avalos 	    last = i;
4345382d832SPeter Avalos 
4355382d832SPeter Avalos 	(void) waddch(obj->text, ' ');
4365382d832SPeter Avalos 	(void) waddnstr(obj->text, line + indx[first], indx[last] - indx[first]);
4375382d832SPeter Avalos 
4385382d832SPeter Avalos 	getyx(obj->text, y, x);
4395382d832SPeter Avalos 	if (y == row) {		/* Clear 'residue' of previous line */
4405382d832SPeter Avalos 	    for (i = 0; i <= width - x; i++) {
4415382d832SPeter Avalos 		(void) waddch(obj->text, ' ');
4425382d832SPeter Avalos 	    }
4435382d832SPeter Avalos 	}
4445382d832SPeter Avalos     }
4455382d832SPeter Avalos }
4465382d832SPeter Avalos 
4475382d832SPeter Avalos /*
4485382d832SPeter Avalos  * Print a new page of text.
4495382d832SPeter Avalos  */
4505382d832SPeter Avalos static void
print_page(MY_OBJ * obj,int height,int width)4515382d832SPeter Avalos print_page(MY_OBJ * obj, int height, int width)
4525382d832SPeter Avalos {
4535382d832SPeter Avalos     int i, passed_end = 0;
4545382d832SPeter Avalos 
4555382d832SPeter Avalos     obj->page_length = 0;
4565382d832SPeter Avalos     for (i = 0; i < height; i++) {
4575382d832SPeter Avalos 	print_line(obj, i, width);
4585382d832SPeter Avalos 	if (!passed_end)
4595382d832SPeter Avalos 	    obj->page_length++;
4605382d832SPeter Avalos 	if (obj->end_reached && !passed_end)
4615382d832SPeter Avalos 	    passed_end = 1;
4625382d832SPeter Avalos     }
4635382d832SPeter Avalos     (void) wnoutrefresh(obj->text);
4645382d832SPeter Avalos     dlg_trace_win(obj->text);
4655382d832SPeter Avalos }
4665382d832SPeter Avalos 
4675382d832SPeter Avalos /*
4685382d832SPeter Avalos  * Print current position
4695382d832SPeter Avalos  */
4705382d832SPeter Avalos static void
print_position(MY_OBJ * obj,WINDOW * win,int height,int width)4715382d832SPeter Avalos print_position(MY_OBJ * obj, WINDOW *win, int height, int width)
4725382d832SPeter Avalos {
4735382d832SPeter Avalos     long fpos;
4745382d832SPeter Avalos     long size;
4755382d832SPeter Avalos     long first = -1;
4765382d832SPeter Avalos 
4775382d832SPeter Avalos     fpos = ftell_obj(obj);
4785382d832SPeter Avalos     if (dialog_vars.tab_correct)
4795382d832SPeter Avalos 	size = tabize(obj, obj->in_buf, &first);
4805382d832SPeter Avalos     else
4815382d832SPeter Avalos 	first = find_first(obj, obj->buf, size = obj->in_buf);
4825382d832SPeter Avalos 
4835382d832SPeter Avalos     dlg_draw_scrollbar(win,
4845382d832SPeter Avalos 		       first,
4855382d832SPeter Avalos 		       fpos - obj->fd_bytes_read + size,
4865382d832SPeter Avalos 		       fpos - obj->fd_bytes_read + size,
4875382d832SPeter Avalos 		       obj->file_size,
4885382d832SPeter Avalos 		       0, PAGE_WIDTH,
4895382d832SPeter Avalos 		       0, PAGE_LENGTH + 1,
4905382d832SPeter Avalos 		       border_attr,
4915382d832SPeter Avalos 		       border_attr);
4925382d832SPeter Avalos }
4935382d832SPeter Avalos 
4945382d832SPeter Avalos /*
4955382d832SPeter Avalos  * Display a dialog box and get the search term from user.
4965382d832SPeter Avalos  */
4975382d832SPeter Avalos static int
get_search_term(WINDOW * dialog,char * input,int height,int width)4985382d832SPeter Avalos get_search_term(WINDOW *dialog, char *input, int height, int width)
4995382d832SPeter Avalos {
5005382d832SPeter Avalos     /* *INDENT-OFF* */
5015382d832SPeter Avalos     static DLG_KEYS_BINDING binding[] = {
5025382d832SPeter Avalos 	INPUTSTR_BINDINGS,
5035382d832SPeter Avalos 	HELPKEY_BINDINGS,
5045382d832SPeter Avalos 	ENTERKEY_BINDINGS,
5055382d832SPeter Avalos 	END_KEYS_BINDING
5065382d832SPeter Avalos     };
5075382d832SPeter Avalos     /* *INDENT-ON* */
5085382d832SPeter Avalos 
5095382d832SPeter Avalos     int old_x, old_y;
5105382d832SPeter Avalos     int box_x, box_y;
5115382d832SPeter Avalos     int box_height, box_width;
5125382d832SPeter Avalos     int offset = 0;
5135382d832SPeter Avalos     int key = 0;
5145382d832SPeter Avalos     int fkey = 0;
5155382d832SPeter Avalos     bool first = TRUE;
5165382d832SPeter Avalos     int result = DLG_EXIT_UNKNOWN;
5175382d832SPeter Avalos     const char *caption = _("Search");
5185382d832SPeter Avalos     int len_caption = dlg_count_columns(caption);
5195382d832SPeter Avalos     const int *indx;
5205382d832SPeter Avalos     int limit;
5215382d832SPeter Avalos     WINDOW *widget;
5225382d832SPeter Avalos 
5235382d832SPeter Avalos     getbegyx(dialog, old_y, old_x);
5245382d832SPeter Avalos 
5255382d832SPeter Avalos     box_height = 1 + (2 * MARGIN);
5265382d832SPeter Avalos     box_width = len_caption + (2 * (MARGIN + 2));
5275382d832SPeter Avalos     box_width = MAX(box_width, 30);
5285382d832SPeter Avalos     box_width = MIN(box_width, getmaxx(dialog) - 2 * MARGIN);
5295382d832SPeter Avalos     len_caption = MIN(len_caption, box_width - (2 * (MARGIN + 1)));
5305382d832SPeter Avalos 
5315382d832SPeter Avalos     box_x = (width - box_width) / 2;
5325382d832SPeter Avalos     box_y = (height - box_height) / 2;
5335382d832SPeter Avalos     widget = dlg_new_modal_window(dialog,
5345382d832SPeter Avalos 				  box_height, box_width,
5355382d832SPeter Avalos 				  old_y + box_y, old_x + box_x);
5365382d832SPeter Avalos     keypad(widget, TRUE);
5375382d832SPeter Avalos     dlg_register_window(widget, "searchbox", binding);
5385382d832SPeter Avalos 
5395382d832SPeter Avalos     dlg_draw_box2(widget, 0, 0, box_height, box_width,
5405382d832SPeter Avalos 		  searchbox_attr,
5415382d832SPeter Avalos 		  searchbox_border_attr,
5425382d832SPeter Avalos 		  searchbox_border2_attr);
5435940c9abSDaniel Fojt     dlg_attrset(widget, searchbox_title_attr);
5445382d832SPeter Avalos     (void) wmove(widget, 0, (box_width - len_caption) / 2);
5455382d832SPeter Avalos 
5465382d832SPeter Avalos     indx = dlg_index_wchars(caption);
5475382d832SPeter Avalos     limit = dlg_limit_columns(caption, len_caption, 0);
5485382d832SPeter Avalos     (void) waddnstr(widget, caption + indx[0], indx[limit] - indx[0]);
5495382d832SPeter Avalos 
5505382d832SPeter Avalos     box_width -= 2;
5515382d832SPeter Avalos     offset = dlg_count_columns(input);
5525382d832SPeter Avalos 
5535382d832SPeter Avalos     while (result == DLG_EXIT_UNKNOWN) {
5545382d832SPeter Avalos 	if (!first) {
5555382d832SPeter Avalos 	    key = dlg_getc(widget, &fkey);
5565382d832SPeter Avalos 	    if (fkey) {
5575382d832SPeter Avalos 		switch (fkey) {
5585382d832SPeter Avalos #ifdef KEY_RESIZE
5595382d832SPeter Avalos 		case KEY_RESIZE:
5605382d832SPeter Avalos 		    result = DLG_EXIT_CANCEL;
5615382d832SPeter Avalos 		    continue;
5625382d832SPeter Avalos #endif
5635382d832SPeter Avalos 		case DLGK_ENTER:
5645382d832SPeter Avalos 		    result = DLG_EXIT_OK;
5655382d832SPeter Avalos 		    continue;
5665382d832SPeter Avalos 		}
5675382d832SPeter Avalos 	    } else if (key == ESC) {
5685382d832SPeter Avalos 		result = DLG_EXIT_ESC;
5695382d832SPeter Avalos 		continue;
5705382d832SPeter Avalos 	    } else if (key == ERR) {
5715382d832SPeter Avalos 		napms(50);
5725382d832SPeter Avalos 		continue;
5735382d832SPeter Avalos 	    }
5745382d832SPeter Avalos 	}
5755382d832SPeter Avalos 	if (dlg_edit_string(input, &offset, key, fkey, first)) {
5765382d832SPeter Avalos 	    dlg_show_string(widget, input, offset, searchbox_attr,
5775382d832SPeter Avalos 			    1, 1, box_width, FALSE, first);
5785382d832SPeter Avalos 	    first = FALSE;
5795382d832SPeter Avalos 	}
5805382d832SPeter Avalos     }
5815382d832SPeter Avalos     dlg_del_window(widget);
5825382d832SPeter Avalos     return result;
5835382d832SPeter Avalos }
5845382d832SPeter Avalos 
5855382d832SPeter Avalos static bool
perform_search(MY_OBJ * obj,int height,int width,int key,char * search_term)5865382d832SPeter Avalos perform_search(MY_OBJ * obj, int height, int width, int key, char *search_term)
5875382d832SPeter Avalos {
5885382d832SPeter Avalos     int dir;
5895382d832SPeter Avalos     bool moved = FALSE;
5905382d832SPeter Avalos 
5915382d832SPeter Avalos     /* set search direction */
5925382d832SPeter Avalos     dir = (key == '/' || key == 'n') ? 1 : 0;
5935382d832SPeter Avalos     if (dir ? !obj->end_reached : !obj->begin_reached) {
5945940c9abSDaniel Fojt 	long tempinx;
5955940c9abSDaniel Fojt 	long fpos;
5965940c9abSDaniel Fojt 	int result;
5975940c9abSDaniel Fojt 	bool found;
5985940c9abSDaniel Fojt 	bool temp, temp1;
5995940c9abSDaniel Fojt 
6005382d832SPeter Avalos 	if (key == 'n' || key == 'N') {
6015382d832SPeter Avalos 	    if (search_term[0] == '\0') {	/* No search term yet */
6025382d832SPeter Avalos 		(void) beep();
6035382d832SPeter Avalos 		return FALSE;
6045382d832SPeter Avalos 	    }
6055382d832SPeter Avalos 	    /* Get search term from user */
6065382d832SPeter Avalos 	} else if ((result = get_search_term(obj->text, search_term,
6075382d832SPeter Avalos 					     PAGE_LENGTH,
6085382d832SPeter Avalos 					     PAGE_WIDTH)) != DLG_EXIT_OK
6095382d832SPeter Avalos 		   || search_term[0] == '\0') {
6105382d832SPeter Avalos #ifdef KEY_RESIZE
6115382d832SPeter Avalos 	    if (result == DLG_EXIT_CANCEL) {
6125382d832SPeter Avalos 		ungetch(key);
6135382d832SPeter Avalos 		ungetch(KEY_RESIZE);
6145382d832SPeter Avalos 		/* FALLTHRU */
6155382d832SPeter Avalos 	    }
6165940c9abSDaniel Fojt #else
6175940c9abSDaniel Fojt 	    (void) result;
6185382d832SPeter Avalos #endif
6195382d832SPeter Avalos 	    /* ESC pressed, or no search term, reprint page to clear box */
6205940c9abSDaniel Fojt 	    dlg_attrset(obj->text, dialog_attr);
6215382d832SPeter Avalos 	    back_lines(obj, obj->page_length);
6225382d832SPeter Avalos 	    return TRUE;
6235382d832SPeter Avalos 	}
6245382d832SPeter Avalos 	/* Save variables for restoring in case search term can't be found */
6255382d832SPeter Avalos 	tempinx = obj->in_buf;
6265382d832SPeter Avalos 	temp = obj->begin_reached;
6275382d832SPeter Avalos 	temp1 = obj->end_reached;
6285382d832SPeter Avalos 	fpos = ftell_obj(obj) - obj->fd_bytes_read;
6295382d832SPeter Avalos 	/* update 'in_buf' to point to next (previous) line before
6305382d832SPeter Avalos 	   forward (backward) searching */
6315382d832SPeter Avalos 	back_lines(obj, (dir
6325382d832SPeter Avalos 			 ? obj->page_length - 1
6335382d832SPeter Avalos 			 : obj->page_length + 1));
6345382d832SPeter Avalos 	if (dir) {		/* Forward search */
6355382d832SPeter Avalos 	    while ((found = match_string(obj, search_term)) == FALSE) {
6365382d832SPeter Avalos 		if (obj->end_reached)
6375382d832SPeter Avalos 		    break;
6385382d832SPeter Avalos 	    }
6395382d832SPeter Avalos 	} else {		/* Backward search */
6405382d832SPeter Avalos 	    while ((found = match_string(obj, search_term)) == FALSE) {
6415382d832SPeter Avalos 		if (obj->begin_reached)
6425382d832SPeter Avalos 		    break;
6435382d832SPeter Avalos 		back_lines(obj, 2L);
6445382d832SPeter Avalos 	    }
6455382d832SPeter Avalos 	}
6465382d832SPeter Avalos 	if (found == FALSE) {	/* not found */
6475382d832SPeter Avalos 	    (void) beep();
6485382d832SPeter Avalos 	    /* Restore program state to that before searching */
6495382d832SPeter Avalos 	    lseek_set(obj, fpos);
6505382d832SPeter Avalos 
6515382d832SPeter Avalos 	    read_high(obj, BUF_SIZE);
6525382d832SPeter Avalos 
6535382d832SPeter Avalos 	    obj->in_buf = tempinx;
6545382d832SPeter Avalos 	    obj->begin_reached = temp;
6555382d832SPeter Avalos 	    obj->end_reached = temp1;
6565382d832SPeter Avalos 	    /* move 'in_buf' to point to start of current page to
6575382d832SPeter Avalos 	     * re-print current page.  Note that 'in_buf' always points
6585382d832SPeter Avalos 	     * to start of next page, so this is necessary
6595382d832SPeter Avalos 	     */
6605382d832SPeter Avalos 	    back_lines(obj, obj->page_length);
6615382d832SPeter Avalos 	} else {		/* Search term found */
6625382d832SPeter Avalos 	    back_lines(obj, 1L);
6635382d832SPeter Avalos 	}
6645382d832SPeter Avalos 	/* Reprint page */
6655940c9abSDaniel Fojt 	dlg_attrset(obj->text, dialog_attr);
6665382d832SPeter Avalos 	moved = TRUE;
6675382d832SPeter Avalos     } else {			/* no need to find */
6685382d832SPeter Avalos 	(void) beep();
6695382d832SPeter Avalos     }
6705382d832SPeter Avalos     return moved;
6715382d832SPeter Avalos }
6725382d832SPeter Avalos 
6735382d832SPeter Avalos /*
6745382d832SPeter Avalos  * Display text from a file in a dialog box.
6755382d832SPeter Avalos  */
6765382d832SPeter Avalos int
dialog_textbox(const char * title,const char * filename,int height,int width)6775940c9abSDaniel Fojt dialog_textbox(const char *title, const char *filename, int height, int width)
6785382d832SPeter Avalos {
6795382d832SPeter Avalos     /* *INDENT-OFF* */
6805382d832SPeter Avalos     static DLG_KEYS_BINDING binding[] = {
6815382d832SPeter Avalos 	HELPKEY_BINDINGS,
6825382d832SPeter Avalos 	ENTERKEY_BINDINGS,
6835382d832SPeter Avalos 	DLG_KEYS_DATA( DLGK_GRID_DOWN,  'J' ),
6845382d832SPeter Avalos 	DLG_KEYS_DATA( DLGK_GRID_DOWN,  'j' ),
6855382d832SPeter Avalos 	DLG_KEYS_DATA( DLGK_GRID_DOWN,  KEY_DOWN ),
6865382d832SPeter Avalos 	DLG_KEYS_DATA( DLGK_GRID_LEFT,  'H' ),
6875382d832SPeter Avalos 	DLG_KEYS_DATA( DLGK_GRID_LEFT,  'h' ),
6885382d832SPeter Avalos 	DLG_KEYS_DATA( DLGK_GRID_LEFT,  KEY_LEFT ),
6895382d832SPeter Avalos 	DLG_KEYS_DATA( DLGK_GRID_RIGHT, 'L' ),
6905382d832SPeter Avalos 	DLG_KEYS_DATA( DLGK_GRID_RIGHT, 'l' ),
6915382d832SPeter Avalos 	DLG_KEYS_DATA( DLGK_GRID_RIGHT, KEY_RIGHT ),
6925382d832SPeter Avalos 	DLG_KEYS_DATA( DLGK_GRID_UP,    'K' ),
6935382d832SPeter Avalos 	DLG_KEYS_DATA( DLGK_GRID_UP,    'k' ),
6945382d832SPeter Avalos 	DLG_KEYS_DATA( DLGK_GRID_UP,    KEY_UP ),
6955382d832SPeter Avalos 	DLG_KEYS_DATA( DLGK_PAGE_FIRST, 'g' ),
6965382d832SPeter Avalos 	DLG_KEYS_DATA( DLGK_PAGE_FIRST, KEY_HOME ),
6975382d832SPeter Avalos 	DLG_KEYS_DATA( DLGK_PAGE_LAST,  'G' ),
6985382d832SPeter Avalos 	DLG_KEYS_DATA( DLGK_PAGE_LAST,  KEY_END ),
6995382d832SPeter Avalos 	DLG_KEYS_DATA( DLGK_PAGE_LAST,  KEY_LL ),
7005940c9abSDaniel Fojt 	DLG_KEYS_DATA( DLGK_PAGE_NEXT,  CHR_SPACE ),
7015382d832SPeter Avalos 	DLG_KEYS_DATA( DLGK_PAGE_NEXT,  KEY_NPAGE ),
7025382d832SPeter Avalos 	DLG_KEYS_DATA( DLGK_PAGE_PREV,  'B' ),
7035382d832SPeter Avalos 	DLG_KEYS_DATA( DLGK_PAGE_PREV,  'b' ),
7045382d832SPeter Avalos 	DLG_KEYS_DATA( DLGK_PAGE_PREV,  KEY_PPAGE ),
7055382d832SPeter Avalos 	DLG_KEYS_DATA( DLGK_BEGIN,	'0' ),
7065382d832SPeter Avalos 	DLG_KEYS_DATA( DLGK_BEGIN,	KEY_BEG ),
7075382d832SPeter Avalos 	DLG_KEYS_DATA( DLGK_FIELD_NEXT, TAB ),
7085382d832SPeter Avalos 	DLG_KEYS_DATA( DLGK_FIELD_PREV, KEY_BTAB ),
7095382d832SPeter Avalos 	END_KEYS_BINDING
7105382d832SPeter Avalos     };
7115382d832SPeter Avalos     /* *INDENT-ON* */
7125382d832SPeter Avalos 
7135382d832SPeter Avalos #ifdef KEY_RESIZE
7145382d832SPeter Avalos     int old_height = height;
7155382d832SPeter Avalos     int old_width = width;
7165382d832SPeter Avalos #endif
7175382d832SPeter Avalos     long fpos;
7185382d832SPeter Avalos     int x, y, cur_x, cur_y;
7195940c9abSDaniel Fojt     int key, fkey;
7205382d832SPeter Avalos     int next = 0;
7215940c9abSDaniel Fojt     int i, passed_end;
7225382d832SPeter Avalos     char search_term[MAX_LEN + 1];
7235382d832SPeter Avalos     MY_OBJ obj;
7245382d832SPeter Avalos     WINDOW *dialog;
7255382d832SPeter Avalos     bool moved;
7265382d832SPeter Avalos     int result = DLG_EXIT_UNKNOWN;
7275382d832SPeter Avalos     int button = dlg_default_button();
7285382d832SPeter Avalos     int min_width = 12;
7295382d832SPeter Avalos 
7305940c9abSDaniel Fojt     DLG_TRACE(("# textbox args:\n"));
7315940c9abSDaniel Fojt     DLG_TRACE2S("title", title);
7325940c9abSDaniel Fojt     DLG_TRACE2S("filename", filename);
7335940c9abSDaniel Fojt     DLG_TRACE2N("height", height);
7345940c9abSDaniel Fojt     DLG_TRACE2N("width", width);
7355940c9abSDaniel Fojt 
7365382d832SPeter Avalos     search_term[0] = '\0';	/* no search term entered yet */
7375382d832SPeter Avalos 
7385382d832SPeter Avalos     memset(&obj, 0, sizeof(obj));
7395382d832SPeter Avalos 
7405382d832SPeter Avalos     obj.begin_reached = TRUE;
7415382d832SPeter Avalos     obj.buffer_first = TRUE;
7425382d832SPeter Avalos     obj.end_reached = FALSE;
7435382d832SPeter Avalos     obj.buttons = dlg_exit_label();
7445382d832SPeter Avalos 
7455382d832SPeter Avalos     /* Open input file for reading */
7465940c9abSDaniel Fojt     if ((obj.fd = open(filename, O_RDONLY)) == -1)
7475940c9abSDaniel Fojt 	dlg_exiterr("Can't open input file %s", filename);
7485382d832SPeter Avalos 
7495382d832SPeter Avalos     /* Get file size. Actually, 'file_size' is the real file size - 1,
7505382d832SPeter Avalos        since it's only the last byte offset from the beginning */
7515382d832SPeter Avalos     lseek_end(&obj, 0L);
7525382d832SPeter Avalos 
7535382d832SPeter Avalos     /* Restore file pointer to beginning of file after getting file size */
7545382d832SPeter Avalos     lseek_set(&obj, 0L);
7555382d832SPeter Avalos 
7565382d832SPeter Avalos     read_high(&obj, BUF_SIZE);
7575382d832SPeter Avalos 
7585382d832SPeter Avalos     dlg_button_layout(obj.buttons, &min_width);
7595382d832SPeter Avalos 
7605382d832SPeter Avalos #ifdef KEY_RESIZE
7615382d832SPeter Avalos   retry:
7625382d832SPeter Avalos #endif
7635382d832SPeter Avalos     moved = TRUE;
7645382d832SPeter Avalos 
7655940c9abSDaniel Fojt     dlg_auto_sizefile(title, filename, &height, &width, 2, min_width);
7665382d832SPeter Avalos     dlg_print_size(height, width);
7675382d832SPeter Avalos     dlg_ctl_size(height, width);
7685382d832SPeter Avalos 
7695382d832SPeter Avalos     x = dlg_box_x_ordinate(width);
7705382d832SPeter Avalos     y = dlg_box_y_ordinate(height);
7715382d832SPeter Avalos 
7725382d832SPeter Avalos     dialog = dlg_new_window(height, width, y, x);
7735382d832SPeter Avalos     dlg_register_window(dialog, "textbox", binding);
7745382d832SPeter Avalos     dlg_register_buttons(dialog, "textbox", obj.buttons);
7755382d832SPeter Avalos 
7765382d832SPeter Avalos     dlg_mouse_setbase(x, y);
7775382d832SPeter Avalos 
7785382d832SPeter Avalos     /* Create window for text region, used for scrolling text */
7795382d832SPeter Avalos     obj.text = dlg_sub_window(dialog, PAGE_LENGTH, PAGE_WIDTH, y + 1, x + 1);
7805382d832SPeter Avalos 
7815382d832SPeter Avalos     /* register the new window, along with its borders */
7825382d832SPeter Avalos     dlg_mouse_mkbigregion(0, 0, PAGE_LENGTH + 2, width, KEY_MAX, 1, 1, 1 /* lines */ );
7835382d832SPeter Avalos     dlg_draw_box2(dialog, 0, 0, height, width, dialog_attr, border_attr, border2_attr);
7845382d832SPeter Avalos     dlg_draw_bottom_box2(dialog, border_attr, border2_attr, dialog_attr);
7855382d832SPeter Avalos     dlg_draw_title(dialog, title);
7865382d832SPeter Avalos 
7875382d832SPeter Avalos     dlg_draw_buttons(dialog, PAGE_LENGTH + 2, 0, obj.buttons, button, FALSE, width);
7885382d832SPeter Avalos     (void) wnoutrefresh(dialog);
7895382d832SPeter Avalos     getyx(dialog, cur_y, cur_x);	/* Save cursor position */
7905382d832SPeter Avalos 
7915382d832SPeter Avalos     dlg_attr_clear(obj.text, PAGE_LENGTH, PAGE_WIDTH, dialog_attr);
7925382d832SPeter Avalos 
7935382d832SPeter Avalos     while (result == DLG_EXIT_UNKNOWN) {
7945940c9abSDaniel Fojt 	int code;
7955382d832SPeter Avalos 
7965382d832SPeter Avalos 	/*
7975382d832SPeter Avalos 	 * Update the screen according to whether we shifted up/down by a line
7985382d832SPeter Avalos 	 * or not.
7995382d832SPeter Avalos 	 */
8005382d832SPeter Avalos 	if (moved) {
8015382d832SPeter Avalos 	    if (next < 0) {
8025382d832SPeter Avalos 		(void) scrollok(obj.text, TRUE);
8035382d832SPeter Avalos 		(void) scroll(obj.text);	/* Scroll text region up one line */
8045382d832SPeter Avalos 		(void) scrollok(obj.text, FALSE);
8055382d832SPeter Avalos 		print_line(&obj, PAGE_LENGTH - 1, PAGE_WIDTH);
8065382d832SPeter Avalos 		(void) wnoutrefresh(obj.text);
8075382d832SPeter Avalos 	    } else if (next > 0) {
8085382d832SPeter Avalos 		/*
8095382d832SPeter Avalos 		 * We don't call print_page() here but use scrolling to ensure
8105382d832SPeter Avalos 		 * faster screen update.  However, 'end_reached' and
8115382d832SPeter Avalos 		 * 'page_length' should still be updated, and 'in_buf' should
8125382d832SPeter Avalos 		 * point to start of next page.  This is done by calling
8135382d832SPeter Avalos 		 * get_line() in the following 'for' loop.
8145382d832SPeter Avalos 		 */
8155382d832SPeter Avalos 		(void) scrollok(obj.text, TRUE);
8165382d832SPeter Avalos 		(void) wscrl(obj.text, -1);	/* Scroll text region down one line */
8175382d832SPeter Avalos 		(void) scrollok(obj.text, FALSE);
8185382d832SPeter Avalos 		obj.page_length = 0;
8195382d832SPeter Avalos 		passed_end = 0;
8205382d832SPeter Avalos 		for (i = 0; i < PAGE_LENGTH; i++) {
8215382d832SPeter Avalos 		    if (!i) {
8225382d832SPeter Avalos 			print_line(&obj, 0, PAGE_WIDTH);	/* print first line of page */
8235382d832SPeter Avalos 			(void) wnoutrefresh(obj.text);
8245382d832SPeter Avalos 		    } else
8255382d832SPeter Avalos 			(void) get_line(&obj);	/* Called to update 'end_reached' and 'in_buf' */
8265382d832SPeter Avalos 		    if (!passed_end)
8275382d832SPeter Avalos 			obj.page_length++;
8285382d832SPeter Avalos 		    if (obj.end_reached && !passed_end)
8295382d832SPeter Avalos 			passed_end = 1;
8305382d832SPeter Avalos 		}
8315382d832SPeter Avalos 	    } else {
8325382d832SPeter Avalos 		print_page(&obj, PAGE_LENGTH, PAGE_WIDTH);
8335382d832SPeter Avalos 	    }
8345382d832SPeter Avalos 	    print_position(&obj, dialog, height, width);
8355382d832SPeter Avalos 	    (void) wmove(dialog, cur_y, cur_x);		/* Restore cursor position */
8365382d832SPeter Avalos 	    wrefresh(dialog);
8375382d832SPeter Avalos 	}
8385382d832SPeter Avalos 	moved = FALSE;		/* assume we'll not move */
8395382d832SPeter Avalos 	next = 0;		/* ...but not scroll by a line */
8405382d832SPeter Avalos 
8415382d832SPeter Avalos 	key = dlg_mouse_wgetch(dialog, &fkey);
8425940c9abSDaniel Fojt 	if (dlg_result_key(key, fkey, &result)) {
8435940c9abSDaniel Fojt 	    if (!dlg_ok_button_key(result, &button, &key, &fkey))
8445382d832SPeter Avalos 		break;
8455940c9abSDaniel Fojt 	}
8465382d832SPeter Avalos 
8475382d832SPeter Avalos 	if (!fkey && (code = dlg_char_to_button(key, obj.buttons)) >= 0) {
8485382d832SPeter Avalos 	    result = dlg_ok_buttoncode(code);
8495382d832SPeter Avalos 	    break;
8505382d832SPeter Avalos 	}
8515382d832SPeter Avalos 
8525382d832SPeter Avalos 	if (fkey) {
8535382d832SPeter Avalos 	    switch (key) {
8545382d832SPeter Avalos 	    default:
8555382d832SPeter Avalos 		if (is_DLGK_MOUSE(key)) {
8565382d832SPeter Avalos 		    result = dlg_exit_buttoncode(key - M_EVENT);
8575382d832SPeter Avalos 		    if (result < 0)
8585382d832SPeter Avalos 			result = DLG_EXIT_OK;
8595382d832SPeter Avalos 		} else {
8605382d832SPeter Avalos 		    beep();
8615382d832SPeter Avalos 		}
8625382d832SPeter Avalos 		break;
8635382d832SPeter Avalos 	    case DLGK_FIELD_NEXT:
8645382d832SPeter Avalos 		button = dlg_next_button(obj.buttons, button);
8655382d832SPeter Avalos 		if (button < 0)
8665382d832SPeter Avalos 		    button = 0;
8675382d832SPeter Avalos 		dlg_draw_buttons(dialog,
8685382d832SPeter Avalos 				 height - 2, 0,
8695382d832SPeter Avalos 				 obj.buttons, button,
8705382d832SPeter Avalos 				 FALSE, width);
8715382d832SPeter Avalos 		break;
8725382d832SPeter Avalos 	    case DLGK_FIELD_PREV:
8735382d832SPeter Avalos 		button = dlg_prev_button(obj.buttons, button);
8745382d832SPeter Avalos 		if (button < 0)
8755382d832SPeter Avalos 		    button = 0;
8765382d832SPeter Avalos 		dlg_draw_buttons(dialog,
8775382d832SPeter Avalos 				 height - 2, 0,
8785382d832SPeter Avalos 				 obj.buttons, button,
8795382d832SPeter Avalos 				 FALSE, width);
8805382d832SPeter Avalos 		break;
8815382d832SPeter Avalos 	    case DLGK_ENTER:
882*a8e38dc0SAntonio Huete Jimenez 		result = dlg_enter_buttoncode(button);
883*a8e38dc0SAntonio Huete Jimenez 		break;
884*a8e38dc0SAntonio Huete Jimenez 	    case DLGK_LEAVE:
885*a8e38dc0SAntonio Huete Jimenez 		result = dlg_ok_buttoncode(button);
8865382d832SPeter Avalos 		break;
8875382d832SPeter Avalos 	    case DLGK_PAGE_FIRST:
8885382d832SPeter Avalos 		if (!obj.begin_reached) {
8895382d832SPeter Avalos 		    obj.begin_reached = 1;
8905382d832SPeter Avalos 		    /* First page not in buffer? */
8915382d832SPeter Avalos 		    fpos = ftell_obj(&obj);
8925382d832SPeter Avalos 
8935382d832SPeter Avalos 		    if (fpos > obj.fd_bytes_read) {
8945382d832SPeter Avalos 			/* Yes, we have to read it in */
8955382d832SPeter Avalos 			lseek_set(&obj, 0L);
8965382d832SPeter Avalos 
8975382d832SPeter Avalos 			read_high(&obj, BUF_SIZE);
8985382d832SPeter Avalos 		    }
8995382d832SPeter Avalos 		    obj.in_buf = 0;
9005382d832SPeter Avalos 		    moved = TRUE;
9015382d832SPeter Avalos 		}
9025382d832SPeter Avalos 		break;
9035382d832SPeter Avalos 	    case DLGK_PAGE_LAST:
9045382d832SPeter Avalos 		obj.end_reached = TRUE;
9055382d832SPeter Avalos 		/* Last page not in buffer? */
9065382d832SPeter Avalos 		fpos = ftell_obj(&obj);
9075382d832SPeter Avalos 
9085382d832SPeter Avalos 		if (fpos < obj.file_size) {
9095382d832SPeter Avalos 		    /* Yes, we have to read it in */
9105382d832SPeter Avalos 		    lseek_end(&obj, -BUF_SIZE);
9115382d832SPeter Avalos 
9125382d832SPeter Avalos 		    read_high(&obj, BUF_SIZE);
9135382d832SPeter Avalos 		}
9145382d832SPeter Avalos 		obj.in_buf = obj.bytes_read;
9155382d832SPeter Avalos 		back_lines(&obj, (long) PAGE_LENGTH);
9165382d832SPeter Avalos 		moved = TRUE;
9175382d832SPeter Avalos 		break;
9185382d832SPeter Avalos 	    case DLGK_GRID_UP:	/* Previous line */
9195382d832SPeter Avalos 		if (!obj.begin_reached) {
9205382d832SPeter Avalos 		    back_lines(&obj, obj.page_length + 1);
9215382d832SPeter Avalos 		    next = 1;
9225382d832SPeter Avalos 		    moved = TRUE;
9235382d832SPeter Avalos 		}
9245382d832SPeter Avalos 		break;
9255382d832SPeter Avalos 	    case DLGK_PAGE_PREV:	/* Previous page */
9265382d832SPeter Avalos 	    case DLGK_MOUSE(KEY_PPAGE):
9275382d832SPeter Avalos 		if (!obj.begin_reached) {
9285382d832SPeter Avalos 		    back_lines(&obj, obj.page_length + PAGE_LENGTH);
9295382d832SPeter Avalos 		    moved = TRUE;
9305382d832SPeter Avalos 		}
9315382d832SPeter Avalos 		break;
9325382d832SPeter Avalos 	    case DLGK_GRID_DOWN:	/* Next line */
9335382d832SPeter Avalos 		if (!obj.end_reached) {
9345382d832SPeter Avalos 		    obj.begin_reached = 0;
9355382d832SPeter Avalos 		    next = -1;
9365382d832SPeter Avalos 		    moved = TRUE;
9375382d832SPeter Avalos 		}
9385382d832SPeter Avalos 		break;
9395382d832SPeter Avalos 	    case DLGK_PAGE_NEXT:	/* Next page */
9405382d832SPeter Avalos 	    case DLGK_MOUSE(KEY_NPAGE):
9415382d832SPeter Avalos 		if (!obj.end_reached) {
9425382d832SPeter Avalos 		    obj.begin_reached = 0;
9435382d832SPeter Avalos 		    moved = TRUE;
9445382d832SPeter Avalos 		}
9455382d832SPeter Avalos 		break;
9465382d832SPeter Avalos 	    case DLGK_BEGIN:	/* Beginning of line */
9475382d832SPeter Avalos 		if (obj.hscroll > 0) {
9485382d832SPeter Avalos 		    obj.hscroll = 0;
9495382d832SPeter Avalos 		    /* Reprint current page to scroll horizontally */
9505382d832SPeter Avalos 		    back_lines(&obj, obj.page_length);
9515382d832SPeter Avalos 		    moved = TRUE;
9525382d832SPeter Avalos 		}
9535382d832SPeter Avalos 		break;
9545382d832SPeter Avalos 	    case DLGK_GRID_LEFT:	/* Scroll left */
9555382d832SPeter Avalos 		if (obj.hscroll > 0) {
9565382d832SPeter Avalos 		    obj.hscroll--;
9575382d832SPeter Avalos 		    /* Reprint current page to scroll horizontally */
9585382d832SPeter Avalos 		    back_lines(&obj, obj.page_length);
9595382d832SPeter Avalos 		    moved = TRUE;
9605382d832SPeter Avalos 		}
9615382d832SPeter Avalos 		break;
9625382d832SPeter Avalos 	    case DLGK_GRID_RIGHT:	/* Scroll right */
9635382d832SPeter Avalos 		if (obj.hscroll < MAX_LEN) {
9645382d832SPeter Avalos 		    obj.hscroll++;
9655382d832SPeter Avalos 		    /* Reprint current page to scroll horizontally */
9665382d832SPeter Avalos 		    back_lines(&obj, obj.page_length);
9675382d832SPeter Avalos 		    moved = TRUE;
9685382d832SPeter Avalos 		}
9695382d832SPeter Avalos 		break;
9705382d832SPeter Avalos #ifdef KEY_RESIZE
9715382d832SPeter Avalos 	    case KEY_RESIZE:
9725940c9abSDaniel Fojt 		dlg_will_resize(dialog);
9735382d832SPeter Avalos 		/* reset data */
9745382d832SPeter Avalos 		height = old_height;
9755382d832SPeter Avalos 		width = old_width;
9765382d832SPeter Avalos 		back_lines(&obj, obj.page_length);
9775382d832SPeter Avalos 		/* repaint */
9785940c9abSDaniel Fojt 		_dlg_resize_cleanup(dialog);
9795382d832SPeter Avalos 		goto retry;
9805382d832SPeter Avalos #endif
9815382d832SPeter Avalos 	    }
9825382d832SPeter Avalos 	} else {
9835382d832SPeter Avalos 	    switch (key) {
9845382d832SPeter Avalos 	    case '/':		/* Forward search */
9855382d832SPeter Avalos 	    case 'n':		/* Repeat forward search */
9865382d832SPeter Avalos 	    case '?':		/* Backward search */
9875382d832SPeter Avalos 	    case 'N':		/* Repeat backward search */
9885382d832SPeter Avalos 		moved = perform_search(&obj, height, width, key, search_term);
9895382d832SPeter Avalos 		fkey = FALSE;
9905382d832SPeter Avalos 		break;
9915382d832SPeter Avalos 	    default:
9925382d832SPeter Avalos 		beep();
9935382d832SPeter Avalos 		break;
9945382d832SPeter Avalos 	    }
9955382d832SPeter Avalos 	}
9965382d832SPeter Avalos     }
9975940c9abSDaniel Fojt     dlg_add_last_key(-1);
9985382d832SPeter Avalos 
9995382d832SPeter Avalos     dlg_del_window(dialog);
10005382d832SPeter Avalos     free(obj.buf);
10015382d832SPeter Avalos     (void) close(obj.fd);
10025382d832SPeter Avalos     dlg_mouse_free_regions();
10035382d832SPeter Avalos     return result;
10045382d832SPeter Avalos }
1005