13515Sache/*
23515Sache *  textbox.c -- implements the text box
33515Sache *
43515Sache *  AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
53515Sache *
63515Sache *  This program is free software; you can redistribute it and/or
73515Sache *  modify it under the terms of the GNU General Public License
83515Sache *  as published by the Free Software Foundation; either version 2
93515Sache *  of the License, or (at your option) any later version.
103515Sache *
113515Sache *  This program is distributed in the hope that it will be useful,
123515Sache *  but WITHOUT ANY WARRANTY; without even the implied warranty of
133515Sache *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
143515Sache *  GNU General Public License for more details.
153515Sache *
163515Sache *  You should have received a copy of the GNU General Public License
173515Sache *  along with this program; if not, write to the Free Software
183515Sache *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
193515Sache */
203515Sache
21114603Sobrien#include <sys/cdefs.h>
22114603Sobrien__FBSDID("$FreeBSD$");
233515Sache
243740Sache#include <dialog.h>
253515Sache#include "dialog.priv.h"
263515Sache
273515Sache
283515Sachestatic void back_lines(int n);
293515Sachestatic void print_page(WINDOW *win, int height, int width);
303515Sachestatic void print_line(WINDOW *win, int row, int width);
313515Sachestatic unsigned char *get_line(void);
323515Sachestatic int get_search_term(WINDOW *win, unsigned char *search_term, int height, int width);
333515Sachestatic void print_position(WINDOW *win, int height, int width);
343515Sache
353515Sache
363515Sachestatic int hscroll = 0, fd, file_size, bytes_read, begin_reached = 1,
373515Sache           end_reached = 0, page_length;
383515Sachestatic unsigned char *buf, *page;
393515Sache
403515Sache
413515Sache/*
423515Sache * Display text from a file in a dialog box.
433515Sache */
443515Sacheint dialog_textbox(unsigned char *title, unsigned char *file, int height, int width)
453515Sache{
463515Sache  int i, x, y, cur_x, cur_y, fpos, key = 0, dir, temp, temp1;
473515Sache#ifdef HAVE_NCURSES
483515Sache  int passed_end;
493515Sache#endif
503515Sache  unsigned char search_term[MAX_LEN+1], *tempptr, *found;
513515Sache  WINDOW *dialog, *text;
523515Sache
534565Sache  if (height < 0 || width < 0) {
544565Sache    fprintf(stderr, "\nAutosizing is impossible in dialog_textbox().\n");
557237Sjkh    return(-1);
564565Sache  }
574565Sache
583515Sache  search_term[0] = '\0';    /* no search term entered yet */
593515Sache
603515Sache  /* Open input file for reading */
613515Sache  if ((fd = open(file, O_RDONLY)) == -1) {
626458Sache    fprintf(stderr, "\nCan't open input file <%s>in dialog_textbox().\n", file);
637237Sjkh    return(-1);
643515Sache  }
653515Sache  /* Get file size. Actually, 'file_size' is the real file size - 1,
663515Sache     since it's only the last byte offset from the beginning */
673515Sache  if ((file_size = lseek(fd, 0, SEEK_END)) == -1) {
683515Sache    fprintf(stderr, "\nError getting file size in dialog_textbox().\n");
697237Sjkh    return(-1);
703515Sache  }
713515Sache  /* Restore file pointer to beginning of file after getting file size */
723515Sache  if (lseek(fd, 0, SEEK_SET) == -1) {
733515Sache    fprintf(stderr, "\nError moving file pointer in dialog_textbox().\n");
747237Sjkh    return(-1);
753515Sache  }
763515Sache  /* Allocate space for read buffer */
773515Sache  if ((buf = malloc(BUF_SIZE+1)) == NULL) {
783515Sache    endwin();
793515Sache    fprintf(stderr, "\nCan't allocate memory in dialog_textbox().\n");
803515Sache    exit(-1);
813515Sache  }
823515Sache  if ((bytes_read = read(fd, buf, BUF_SIZE)) == -1) {
833515Sache    fprintf(stderr, "\nError reading file in dialog_textbox().\n");
847237Sjkh    return(-1);
853515Sache  }
863515Sache  buf[bytes_read] = '\0';    /* mark end of valid data */
873515Sache  page = buf;    /* page is pointer to start of page to be displayed */
883515Sache
894658Sache  if (width > COLS)
904658Sache	width = COLS;
914658Sache  if (height > LINES)
924658Sache	height = LINES;
933515Sache  /* center dialog box on screen */
9413135Sjkh  x = DialogX ? DialogX : (COLS - width)/2;
9513135Sjkh  y = DialogY ? DialogY : (LINES - height)/2;
963515Sache
973515Sache#ifdef HAVE_NCURSES
983515Sache  if (use_shadow)
993515Sache    draw_shadow(stdscr, y, x, height, width);
1003515Sache#endif
1013515Sache  dialog = newwin(height, width, y, x);
1024024Sache  if (dialog == NULL) {
1034024Sache    endwin();
1044024Sache    fprintf(stderr, "\nnewwin(%d,%d,%d,%d) failed, maybe wrong dims\n", height,width,y,x);
1054024Sache    exit(1);
1064024Sache  }
1073515Sache  keypad(dialog, TRUE);
1083515Sache
1093515Sache  /* Create window for text region, used for scrolling text */
1103515Sache/*  text = newwin(height-4, width-2, y+1, x+1); */
1113515Sache  text = subwin(dialog, height-4, width-2, y+1, x+1);
1124024Sache  if (text == NULL) {
1134024Sache    endwin();
1144024Sache    fprintf(stderr, "\nsubwin(dialog,%d,%d,%d,%d) failed, maybe wrong dims\n", height-4,width-2,y+1,x+1);
1154024Sache    exit(1);
1164024Sache  }
1173515Sache  keypad(text, TRUE);
1183515Sache
1193515Sache  draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr);
1203515Sache
1213515Sache  wattrset(dialog, border_attr);
1223515Sache  wmove(dialog, height-3, 0);
1233515Sache  waddch(dialog, ACS_LTEE);
1243515Sache  for (i = 0; i < width-2; i++)
1253515Sache    waddch(dialog, ACS_HLINE);
1263515Sache  wattrset(dialog, dialog_attr);
1273515Sache  waddch(dialog, ACS_RTEE);
1283515Sache  wmove(dialog, height-2, 1);
1293515Sache  for (i = 0; i < width-2; i++)
1303515Sache    waddch(dialog, ' ');
1313515Sache
1323515Sache  if (title != NULL) {
1333515Sache    wattrset(dialog, title_attr);
1343515Sache    wmove(dialog, 0, (width - strlen(title))/2 - 1);
1353515Sache    waddch(dialog, ' ');
1363515Sache    waddstr(dialog, title);
1373515Sache    waddch(dialog, ' ');
1383515Sache  }
1396458Sache  display_helpline(dialog, height-1, width);
1406458Sache
14120359Sjkh  print_button(dialog, "  OK  ", height-2, width/2-6, TRUE);
1423515Sache  wnoutrefresh(dialog);
1433515Sache  getyx(dialog, cur_y, cur_x);    /* Save cursor position */
1443515Sache
1453515Sache  /* Print first page of text */
1463515Sache  attr_clear(text, height-4, width-2, dialog_attr);
1473515Sache  print_page(text, height-4, width-2);
1483515Sache  print_position(dialog, height, width);
1493515Sache  wmove(dialog, cur_y, cur_x);    /* Restore cursor position */
1503515Sache  wrefresh(dialog);
1513515Sache
15279843Seric  while ((key != ESC) && (key != '\n') && (key != '\r') && (key != ' ')) {
1533515Sache    key = wgetch(dialog);
1543515Sache    switch (key) {
1553515Sache      case 'E':    /* Exit */
1563515Sache      case 'e':
1573515Sache        delwin(dialog);
1583515Sache        free(buf);
1593515Sache        close(fd);
1603515Sache        return 0;
1613515Sache      case 'g':    /* First page */
1623515Sache      case KEY_HOME:
1633515Sache        if (!begin_reached) {
1643515Sache          begin_reached = 1;
1653515Sache          /* First page not in buffer? */
1663515Sache          if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) {
1673515Sache            endwin();
1683515Sache            fprintf(stderr, "\nError moving file pointer in dialog_textbox().\n");
1693515Sache            exit(-1);
1703515Sache          }
1713515Sache          if (fpos > bytes_read) {    /* Yes, we have to read it in */
1723515Sache            if (lseek(fd, 0, SEEK_SET) == -1) {
1733515Sache              endwin();
1743515Sache              fprintf(stderr, "\nError moving file pointer in dialog_textbox().\n");
1753515Sache              exit(-1);
1763515Sache            }
1773515Sache            if ((bytes_read = read(fd, buf, BUF_SIZE)) == -1) {
1783515Sache              endwin();
1793515Sache              fprintf(stderr, "\nError reading file in dialog_textbox().\n");
1803515Sache              exit(-1);
1813515Sache            }
1823515Sache            buf[bytes_read] = '\0';
1833515Sache          }
1843515Sache          page = buf;
1853515Sache          print_page(text, height-4, width-2);
1863515Sache          print_position(dialog, height, width);
1873515Sache          wmove(dialog, cur_y, cur_x);    /* Restore cursor position */
1883515Sache          wrefresh(dialog);
1893515Sache        }
1903515Sache        break;
1913515Sache      case 'G':    /* Last page */
1923515Sache#ifdef HAVE_NCURSES
1933515Sache      case KEY_END:
1943515Sache#endif
1953515Sache        end_reached = 1;
1963515Sache        /* Last page not in buffer? */
1973515Sache        if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) {
1983515Sache          endwin();
1993515Sache          fprintf(stderr, "\nError moving file pointer in dialog_textbox().\n");
2003515Sache          exit(-1);
2013515Sache        }
2023515Sache        if (fpos < file_size) {    /* Yes, we have to read it in */
2033515Sache          if (lseek(fd, -BUF_SIZE, SEEK_END) == -1) {
2043515Sache            endwin();
2053515Sache            fprintf(stderr, "\nError moving file pointer in dialog_textbox().\n");
2063515Sache            exit(-1);
2073515Sache          }
2083515Sache          if ((bytes_read = read(fd, buf, BUF_SIZE)) == -1) {
2093515Sache            endwin();
2103515Sache            fprintf(stderr, "\nError reading file in dialog_textbox().\n");
2113515Sache            exit(-1);
2123515Sache          }
2133515Sache          buf[bytes_read] = '\0';
2143515Sache        }
2153515Sache        page = buf + bytes_read;
2163515Sache        back_lines(height-4);
2173515Sache        print_page(text, height-4, width-2);
2183515Sache        print_position(dialog, height, width);
2193515Sache        wmove(dialog, cur_y, cur_x);    /* Restore cursor position */
2203515Sache        wrefresh(dialog);
2213515Sache        break;
2223515Sache      case 'K':    /* Previous line */
2233515Sache      case 'k':
22421697Sjkh      case '\020':	/* ^P */
2253515Sache      case KEY_UP:
2263515Sache        if (!begin_reached) {
2273515Sache          back_lines(page_length+1);
2283515Sache#ifdef HAVE_NCURSES
2293515Sache          /* We don't call print_page() here but use scrolling to ensure
2303515Sache             faster screen update. However, 'end_reached' and 'page_length'
2313515Sache             should still be updated, and 'page' should point to start of
2323515Sache             next page. This is done by calling get_line() in the following
2333515Sache             'for' loop. */
2343515Sache          scrollok(text, TRUE);
2353515Sache          wscrl(text, -1);    /* Scroll text region down one line */
2363515Sache          scrollok(text, FALSE);
2373515Sache          page_length = 0;
2383515Sache          passed_end = 0;
2393515Sache          for (i = 0; i < height-4; i++) {
2403515Sache            if (!i) {
2413515Sache              print_line(text, 0, width-2);    /* print first line of page */
2423515Sache              wnoutrefresh(text);
2433515Sache            }
2443515Sache            else
2453515Sache              get_line();    /* Called to update 'end_reached' and 'page' */
2463515Sache            if (!passed_end)
2473515Sache              page_length++;
2483515Sache            if (end_reached && !passed_end)
2493515Sache              passed_end = 1;
2503515Sache          }
2513515Sache#else
2523515Sache          print_page(text, height-4, width-2);
2533515Sache#endif
2543515Sache          print_position(dialog, height, width);
2553515Sache          wmove(dialog, cur_y, cur_x);    /* Restore cursor position */
2563515Sache          wrefresh(dialog);
2573515Sache        }
2583515Sache        break;
2593515Sache      case 'B':    /* Previous page */
2603515Sache      case 'b':
2613515Sache      case KEY_PPAGE:
2623515Sache        if (!begin_reached) {
2633515Sache          back_lines(page_length + height-4);
2643515Sache          print_page(text, height-4, width-2);
2653515Sache          print_position(dialog, height, width);
2663515Sache          wmove(dialog, cur_y, cur_x);    /* Restore cursor position */
2673515Sache          wrefresh(dialog);
2683515Sache        }
2693515Sache        break;
2703515Sache      case 'J':    /* Next line */
2713515Sache      case 'j':
27221697Sjkh      case '\016':	/* ^N */
2733515Sache      case KEY_DOWN:
2743515Sache        if (!end_reached) {
2753515Sache          begin_reached = 0;
2763515Sache          scrollok(text, TRUE);
2773515Sache          scroll(text);    /* Scroll text region up one line */
2783515Sache          scrollok(text, FALSE);
2793515Sache          print_line(text, height-5, width-2);
2803515Sache#ifndef HAVE_NCURSES
2813515Sache          wmove(text, height-5, 0);
2823515Sache          waddch(text, ' ');
2833515Sache          wmove(text, height-5, width-3);
2843515Sache          waddch(text, ' ');
2853515Sache#endif
2863515Sache          wnoutrefresh(text);
2873515Sache          print_position(dialog, height, width);
2883515Sache          wmove(dialog, cur_y, cur_x);    /* Restore cursor position */
2893515Sache          wrefresh(dialog);
2903515Sache        }
2913515Sache        break;
29280372Seric      case 'F':    /* Next page */
29380372Seric      case 'f':
2943515Sache      case KEY_NPAGE:
2953515Sache        if (!end_reached) {
2963515Sache          begin_reached = 0;
2973515Sache          print_page(text, height-4, width-2);
2983515Sache          print_position(dialog, height, width);
2993515Sache          wmove(dialog, cur_y, cur_x);    /* Restore cursor position */
3003515Sache          wrefresh(dialog);
3013515Sache        }
3023515Sache        break;
3033515Sache      case '0':    /* Beginning of line */
3043515Sache      case 'H':    /* Scroll left */
3053515Sache      case 'h':
3063515Sache      case KEY_LEFT:
3073515Sache        if (hscroll > 0) {
3083515Sache          if (key == '0')
3093515Sache            hscroll = 0;
3103515Sache          else
3113515Sache            hscroll--;
3123515Sache          /* Reprint current page to scroll horizontally */
3133515Sache          back_lines(page_length);
3143515Sache          print_page(text, height-4, width-2);
3153515Sache          wmove(dialog, cur_y, cur_x);    /* Restore cursor position */
3163515Sache          wrefresh(dialog);
3173515Sache        }
3183515Sache        break;
3193515Sache      case 'L':    /* Scroll right */
3203515Sache      case 'l':
3213515Sache      case KEY_RIGHT:
3223515Sache        if (hscroll < MAX_LEN) {
3233515Sache          hscroll++;
3243515Sache          /* Reprint current page to scroll horizontally */
3253515Sache          back_lines(page_length);
3263515Sache          print_page(text, height-4, width-2);
3273515Sache          wmove(dialog, cur_y, cur_x);    /* Restore cursor position */
3283515Sache          wrefresh(dialog);
3293515Sache        }
3303515Sache        break;
3313515Sache      case '/':    /* Forward search */
3323515Sache      case 'n':    /* Repeat forward search */
3333515Sache      case '?':    /* Backward search */
3343515Sache      case 'N':    /* Repeat backward search */
3353515Sache        /* set search direction */
3363515Sache        dir = (key == '/' || key == 'n') ? 1 : 0;
3373515Sache        if (dir ? !end_reached : !begin_reached) {
3383515Sache          if (key == 'n' || key == 'N') {
3393515Sache            if (search_term[0] == '\0') {    /* No search term yet */
3403515Sache              fprintf(stderr, "\a");    /* beep */
3413515Sache              break;
3423515Sache            }
3433515Sache	  }
3443515Sache          else    /* Get search term from user */
3453515Sache            if (get_search_term(text, search_term, height-4, width-2) == -1) {
3463515Sache              /* ESC pressed in get_search_term(). Reprint page to clear box */
3473515Sache              wattrset(text, dialog_attr);
3483515Sache              back_lines(page_length);
3493515Sache              print_page(text, height-4, width-2);
3503515Sache              wmove(dialog, cur_y, cur_x);    /* Restore cursor position */
3513515Sache              wrefresh(dialog);
3523515Sache              break;
3533515Sache            }
3543515Sache          /* Save variables for restoring in case search term can't be found */
3553515Sache          tempptr = page;
3563515Sache          temp = begin_reached;
3573515Sache          temp1 = end_reached;
3583515Sache          if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) {
3593515Sache            endwin();
3603515Sache            fprintf(stderr, "\nError moving file pointer in dialog_textbox().\n");
3613515Sache            exit(-1);
3623515Sache          }
3633515Sache          fpos -= bytes_read;
3643515Sache          /* update 'page' to point to next (previous) line before
3653515Sache             forward (backward) searching */
3663515Sache          back_lines(dir ? page_length-1 : page_length+1);
3673515Sache          found = NULL;
3683515Sache          if (dir)    /* Forward search */
3693515Sache            while((found = strstr(get_line(), search_term)) == NULL) {
3703515Sache              if (end_reached)
3713515Sache                break;
3723515Sache	    }
3733515Sache          else    /* Backward search */
3743515Sache            while((found = strstr(get_line(), search_term)) == NULL) {
3753515Sache              if (begin_reached)
3763515Sache                break;
3773515Sache              back_lines(2);
3783515Sache            }
3793515Sache          if (found == NULL) {    /* not found */
3803515Sache            fprintf(stderr, "\a");    /* beep */
3813515Sache            /* Restore program state to that before searching */
3823515Sache            if (lseek(fd, fpos, SEEK_SET) == -1) {
3833515Sache              endwin();
3843515Sache              fprintf(stderr, "\nError moving file pointer in dialog_textbox().\n");
3853515Sache              exit(-1);
3863515Sache            }
3873515Sache            if ((bytes_read = read(fd, buf, BUF_SIZE)) == -1) {
3883515Sache              endwin();
3893515Sache              fprintf(stderr, "\nError reading file in dialog_textbox().\n");
3903515Sache              exit(-1);
3913515Sache            }
3923515Sache            buf[bytes_read] = '\0';
3933515Sache            page = tempptr;
3943515Sache            begin_reached = temp;
3953515Sache            end_reached = temp1;
3963515Sache            /* move 'page' to point to start of current page in order to
3973515Sache               re-print current page. Note that 'page' always points to
3983515Sache               start of next page, so this is necessary */
3993515Sache            back_lines(page_length);
4003515Sache          }
4013515Sache          else    /* Search term found */
4023515Sache            back_lines(1);
4033515Sache          /* Reprint page */
4043515Sache          wattrset(text, dialog_attr);
4053515Sache          print_page(text, height-4, width-2);
4063515Sache          if (found != NULL)
4073515Sache            print_position(dialog, height, width);
4083515Sache          wmove(dialog, cur_y, cur_x);    /* Restore cursor position */
4093515Sache          wrefresh(dialog);
4103515Sache        }
4113515Sache        else    /* no need to find */
4123515Sache          fprintf(stderr, "\a");    /* beep */
4133515Sache        break;
4143515Sache      case ESC:
4153515Sache        break;
4166458Sache    case KEY_F(1):
4176458Sache	display_helpfile();
4186458Sache	break;
4193515Sache    }
4203515Sache  }
4213515Sache
4223515Sache  delwin(dialog);
4233515Sache  free(buf);
4243515Sache  close(fd);
42598195Sdougb  return (key == ESC ? -1 : 0);
4263515Sache}
4273515Sache/* End of dialog_textbox() */
4283515Sache
4293515Sache
4303515Sache/*
4313515Sache * Go back 'n' lines in text file. Called by dialog_textbox().
4323515Sache * 'page' will be updated to point to the desired line in 'buf'.
4333515Sache */
4343515Sachestatic void back_lines(int n)
4353515Sache{
4363515Sache  int i, fpos;
4373515Sache
4383515Sache  begin_reached = 0;
4393515Sache  /* We have to distinguish between end_reached and !end_reached since at end
4403515Sache     of file, the line is not ended by a '\n'. The code inside 'if' basically
4413515Sache     does a '--page' to move one character backward so as to skip '\n' of the
4423515Sache     previous line */
4433515Sache  if (!end_reached) {
4443515Sache    /* Either beginning of buffer or beginning of file reached? */
4453515Sache    if (page == buf) {
4463515Sache      if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) {
4473515Sache        endwin();
4483515Sache        fprintf(stderr, "\nError moving file pointer in back_lines().\n");
4493515Sache        exit(-1);
4503515Sache      }
4513515Sache      if (fpos > bytes_read) {    /* Not beginning of file yet */
4523515Sache        /* We've reached beginning of buffer, but not beginning of file yet,
4533515Sache           so read previous part of file into buffer. Note that we only
4543515Sache           move backward for BUF_SIZE/2 bytes, but not BUF_SIZE bytes to
4553515Sache           avoid re-reading again in print_page() later */
4563515Sache        /* Really possible to move backward BUF_SIZE/2 bytes? */
4573515Sache        if (fpos < BUF_SIZE/2 + bytes_read) {
4583515Sache          /* No, move less then */
4593515Sache          if (lseek(fd, 0, SEEK_SET) == -1) {
4603515Sache            endwin();
4613515Sache            fprintf(stderr, "\nError moving file pointer in back_lines().\n");
4623515Sache            exit(-1);
4633515Sache          }
4643515Sache          page = buf + fpos - bytes_read;
4653515Sache        }
4663515Sache        else {    /* Move backward BUF_SIZE/2 bytes */
4673515Sache          if (lseek(fd, -(BUF_SIZE/2 + bytes_read), SEEK_CUR) == -1) {
4683515Sache            endwin();
4693515Sache            fprintf(stderr, "\nError moving file pointer in back_lines().\n");
4703515Sache            exit(-1);
4713515Sache          }
4723515Sache          page = buf + BUF_SIZE/2;
4733515Sache        }
4743515Sache        if ((bytes_read = read(fd, buf, BUF_SIZE)) == -1) {
4753515Sache          endwin();
4763515Sache          fprintf(stderr, "\nError reading file in back_lines().\n");
4773515Sache          exit(-1);
4783515Sache        }
4793515Sache        buf[bytes_read] = '\0';
4803515Sache      }
4813515Sache      else {    /* Beginning of file reached */
4823515Sache        begin_reached = 1;
4833515Sache        return;
4843515Sache      }
4853515Sache    }
4863515Sache    if (*(--page) != '\n') {    /* '--page' here */
4873515Sache      /* Something's wrong... */
4883515Sache      endwin();
4893515Sache      fprintf(stderr, "\nInternal error in back_lines().\n");
4903515Sache      exit(-1);
4913515Sache    }
4923515Sache  }
4933515Sache
4943515Sache  /* Go back 'n' lines */
4953515Sache  for (i = 0; i < n; i++)
4963515Sache    do {
4973515Sache      if (page == buf) {
4983515Sache        if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) {
4993515Sache          endwin();
5003515Sache          fprintf(stderr, "\nError moving file pointer in back_lines().\n");
5013515Sache          exit(-1);
5023515Sache        }
5033515Sache        if (fpos > bytes_read) {
5043515Sache          /* Really possible to move backward BUF_SIZE/2 bytes? */
5053515Sache          if (fpos < BUF_SIZE/2 + bytes_read) {
5063515Sache            /* No, move less then */
5073515Sache            if (lseek(fd, 0, SEEK_SET) == -1) {
5083515Sache              endwin();
5093515Sache              fprintf(stderr, "\nError moving file pointer in back_lines().\n");
5103515Sache              exit(-1);
5113515Sache            }
5123515Sache            page = buf + fpos - bytes_read;
5133515Sache          }
5143515Sache          else {    /* Move backward BUF_SIZE/2 bytes */
5153515Sache            if (lseek(fd, -(BUF_SIZE/2 + bytes_read), SEEK_CUR) == -1) {
5163515Sache              endwin();
5173515Sache              fprintf(stderr, "\nError moving file pointer in back_lines().\n");
5183515Sache              exit(-1);
5193515Sache            }
5203515Sache            page = buf + BUF_SIZE/2;
5213515Sache          }
5223515Sache          if ((bytes_read = read(fd, buf, BUF_SIZE)) == -1) {
5233515Sache            endwin();
5243515Sache            fprintf(stderr, "\nError reading file in back_lines().\n");
5253515Sache            exit(-1);
5263515Sache          }
5273515Sache          buf[bytes_read] = '\0';
5283515Sache        }
5293515Sache        else {    /* Beginning of file reached */
5303515Sache          begin_reached = 1;
5313515Sache          return;
5323515Sache        }
5333515Sache      }
5343515Sache    } while (*(--page) != '\n');
5353515Sache  page++;
5363515Sache}
5373515Sache/* End of back_lines() */
5383515Sache
5393515Sache
5403515Sache/*
5413515Sache * Print a new page of text. Called by dialog_textbox().
5423515Sache */
5433515Sachestatic void print_page(WINDOW *win, int height, int width)
5443515Sache{
5453515Sache  int i, passed_end = 0;
5463515Sache
5473515Sache  page_length = 0;
5483515Sache  for (i = 0; i < height; i++) {
5493515Sache    print_line(win, i, width);
5503515Sache    if (!passed_end)
5513515Sache      page_length++;
5523515Sache    if (end_reached && !passed_end)
5533515Sache      passed_end = 1;
5543515Sache  }
5553515Sache  wnoutrefresh(win);
5563515Sache}
5573515Sache/* End of print_page() */
5583515Sache
5593515Sache
5603515Sache/*
5613515Sache * Print a new line of text. Called by dialog_textbox() and print_page().
5623515Sache */
5633515Sachestatic void print_line(WINDOW *win, int row, int width)
5643515Sache{
5653515Sache  int i, y, x;
5663515Sache  unsigned char *line;
5673515Sache
5683515Sache  line = get_line();
5693515Sache  line += MIN(strlen(line),hscroll);    /* Scroll horizontally */
5703515Sache  wmove(win, row, 0);    /* move cursor to correct line */
5713515Sache  waddch(win,' ');
5723515Sache#ifdef HAVE_NCURSES
5733515Sache  waddnstr(win, line, MIN(strlen(line),width-2));
5743515Sache#else
5753515Sache  line[MIN(strlen(line),width-2)] = '\0';
5763515Sache  waddstr(win, line);
5773515Sache#endif
5783515Sache
5793515Sache  getyx(win, y, x);
5803515Sache  /* Clear 'residue' of previous line */
5813515Sache  for (i = 0; i < width-x; i++)
5823515Sache    waddch(win, ' ');
5833515Sache}
5843515Sache/* End of print_line() */
5853515Sache
5863515Sache
5873515Sache/*
5883515Sache * Return current line of text. Called by dialog_textbox() and print_line().
5893515Sache * 'page' should point to start of current line before calling, and will be
5903515Sache * updated to point to start of next line.
5913515Sache */
5923515Sachestatic unsigned char *get_line(void)
5933515Sache{
5943515Sache  int i = 0, fpos;
5953515Sache  static unsigned char line[MAX_LEN+1];
5963515Sache
5973515Sache  end_reached = 0;
5983515Sache  while (*page != '\n') {
5993515Sache    if (*page == '\0') {    /* Either end of file or end of buffer reached */
6003515Sache      if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) {
6013515Sache        endwin();
6023515Sache        fprintf(stderr, "\nError moving file pointer in get_line().\n");
6033515Sache        exit(-1);
6043515Sache      }
6053515Sache      if (fpos < file_size) {    /* Not end of file yet */
6063515Sache        /* We've reached end of buffer, but not end of file yet, so read next
6073515Sache           part of file into buffer */
6083515Sache        if ((bytes_read = read(fd, buf, BUF_SIZE)) == -1) {
6093515Sache          endwin();
6103515Sache          fprintf(stderr, "\nError reading file in get_line().\n");
6113515Sache          exit(-1);
6123515Sache        }
6133515Sache        buf[bytes_read] = '\0';
6143515Sache        page = buf;
6153515Sache      }
6163515Sache      else {
6173515Sache        if (!end_reached)
6183515Sache          end_reached = 1;
6193515Sache        break;
6203515Sache      }
6213515Sache    }
6223515Sache    else
6233515Sache      if (i < MAX_LEN)
6243515Sache        line[i++] = *(page++);
6253515Sache      else {
6263515Sache        if (i == MAX_LEN)  /* Truncate lines longer than MAX_LEN characters */
6273515Sache          line[i++] = '\0';
6283515Sache        page++;
6293515Sache      }
6303515Sache  }
6313515Sache  if (i <= MAX_LEN)
6323515Sache    line[i] = '\0';
6333515Sache  if (!end_reached)
6343515Sache    page++;    /* move pass '\n' */
6353515Sache
6363515Sache  return line;
6373515Sache}
6383515Sache/* End of get_line() */
6393515Sache
6403515Sache
6413515Sache/*
6423515Sache * Display a dialog box and get the search term from user
6433515Sache */
6443515Sachestatic int get_search_term(WINDOW *win, unsigned char *search_term, int height, int width)
6453515Sache{
6463754Sache  int x, y, key = 0, first,
6473515Sache      box_height = 3, box_width = 30;
6483515Sache
6493515Sache  x = (width - box_width)/2;
6503515Sache  y = (height - box_height)/2;
6513515Sache#ifdef HAVE_NCURSES
6523515Sache  if (use_shadow)
6533515Sache    draw_shadow(win, y, x, box_height, box_width);
6543515Sache#endif
6553515Sache  draw_box(win, y, x, box_height, box_width, dialog_attr, searchbox_border_attr);
6563515Sache  wattrset(win, searchbox_title_attr);
6573515Sache  wmove(win, y, x+box_width/2-4);
6583515Sache  waddstr(win, " Search ");
6594591Sache  wattrset(win, dialog_attr);
6603515Sache
6613515Sache  search_term[0] = '\0';
6623754Sache
6633754Sache  first = 1;
6643515Sache  while (key != ESC) {
66520442Sjkh    key = line_edit(win, y+1, x+1, -1, box_width-2, searchbox_attr, first, search_term, 0);
6663754Sache    first = 0;
6673515Sache    switch (key) {
6683515Sache      case '\n':
6693515Sache        if (search_term[0] != '\0')
6703515Sache          return 0;
6713515Sache        break;
6723515Sache      case ESC:
6733754Sache	break;
6743515Sache    }
6753515Sache  }
6763515Sache
6773515Sache  return -1;    /* ESC pressed */
6783515Sache}
6793515Sache/* End of get_search_term() */
6803515Sache
6813515Sache
6823515Sache/*
6833515Sache * Print current position
6843515Sache */
6853515Sachestatic void print_position(WINDOW *win, int height, int width)
6863515Sache{
6873515Sache  int fpos, percent;
6883515Sache
6893515Sache  if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) {
6903515Sache    endwin();
6913515Sache    fprintf(stderr, "\nError moving file pointer in print_position().\n");
6923515Sache    exit(-1);
6933515Sache  }
6943515Sache  wattrset(win, position_indicator_attr);
6953515Sache  percent = !file_size ? 100 : ((fpos-bytes_read+page-buf)*100)/file_size;
6963515Sache  wmove(win, height-3, width-9);
6973515Sache  wprintw(win, "(%3d%%)", percent);
6983515Sache}
6993515Sache/* End of print_position() */
700