/*************************************************************************
 ***                        input.c                      (JJB TEMPLAR) ***
 *** Date modifications begun: 7/8/89.                                 ***
 *** Last modified: 27/8/89.                                           ***
 *************************************************************************/
/*** High level routines dealing with getting lines of input from the  ***
 *** file being viewed. When we speak of "lines" here, we mean         ***
 *** PRINTABLE lines; lines processed with respect to the screen width.***
 *** We use the term "raw line" to refer to lines simply delimited by  ***
 *** newlines; not processed with respect to screen width.             ***
 *************************************************************************/

#include "less.h"

extern int  do_bs;
extern int  squeeze;
extern char *line;

int     page_break;

LONG    forw_line(curr_pos) /*===========================================*/
LONG    curr_pos;           /* Get next line, given old position.        */
{
LONG        new_pos;
register int c;

    if ((curr_pos == NULL_POSITION) || ch_seek(curr_pos)) return(NULL_POSITION);
    prewind();
    if (page_break) {
        new_pos = curr_pos;
        goto PAGE_SKIP;
    }
    if ((c = ch_forw_get()) == EOF) return(NULL_POSITION);
    if (c == '') {                /* Must be first char on line */
        page_break = 1;
    }

    for (;;) {
      /* Check for EOF too, since file may not end with '\n' */
        if ((c == '\n') || (c == EOF)) {
            new_pos = ch_tell();    /* End of line */
            break;
        }

      /* Append the char to the line and get the next char. */
        if (pappend(c)) {
          /* The char won't fit in the line; the line
             is too long to print in the screen width.
             End the line here.          */
            new_pos = ch_tell() - 1;
            break;
        }
        c = ch_forw_get();
    }
PAGE_SKIP:
    pappend('\0');

    if (squeeze && !(*line) && !page_break) {
        /* This line is blank.
           Skip down to the last contiguous blank line
           and pretend it is the one which we are returning. */
        while ((c = ch_forw_get()) == '\n') ;
        if (c != EOF) ch_back_get();
        new_pos = ch_tell();
    }
    return(new_pos);
}

LONG    back_line(curr_pos) /*===========================================*/
LONG    curr_pos;           /* Get previous line.                        */
{
LONG    new_pos, begin_new_pos;
register int    c;

    if ((curr_pos == NULL_POSITION) || (curr_pos <= 0) || ch_seek(curr_pos-1))
        return (NULL_POSITION);

    if (page_break) {
        begin_new_pos = curr_pos;
        prewind();
        goto PAGE_BREAK;
    }

    if (squeeze) {              /* page_break disables squeeze */
      /* Find out if the "current" line was blank. */
        ch_forw_get();          /* Skip the newline */
        c = ch_forw_get();      /* First char of "current" line */
        ch_back_get();          /* Restore our position */
        ch_back_get();

        if (c == '\n') {
          /* The "current" line was blank.
             Skip over any preceeding blank lines,
             since we skipped them in forw_line(). */
            while ((c = ch_back_get()) == '\n') ;
            if (c == EOF) return (NULL_POSITION);
            ch_forw_get();
        }
    }

  /* Scan backwards until we hit the beginning of the line. */
    for (;;) {
        c = ch_back_get();
        if (c == '\n') {
          /* This is the newline ending the previous line.
             We have hit the beginning of the line. */
            new_pos = ch_tell() + 1;
            break;
        }
        if (c == EOF) {
          /* We have hit the beginning of the file.
             This must be the first line in the file.
             This must, of course, be the beginning of the line. */
            new_pos = 0;
            break;
        }
    }

  /* Now scan forwards from the beginning of this line.
     We keep discarding "printable lines" (based on screen width)
     until we reach the curr_pos. */

    if (ch_seek(new_pos)) return(NULL_POSITION);
loop:
    begin_new_pos = new_pos;
    prewind();

    do {
        c = ch_forw_get();
        new_pos++;
        if (c == '\n') break;
        if (pappend(c)) {
          /* Got a full printable line, but we haven't reached our curr_pos yet.
             Discard the line and start a new one. */
            pappend('\0');
            ch_back_get();
            new_pos--;
            goto loop;      /* Hey hey hey! */
        }
    } while (new_pos < curr_pos);
PAGE_BREAK:
    pappend('\0');

    if (*line == '') page_break = 1;

    return(begin_new_pos);
}
