/*************************************************************************
 ***                        line.c                       (JJB TEMPLAR) ***
 *** Date modifications begun: 7/8/89.                                 ***
 *** Last modified: 9/8/89.                                            ***
 *************************************************************************/
/*** Routines to manipulate the "line buffer". The line buffer holds a ***
 *** line of output as it is being built in preparation for output to  ***
 *** the screen. We keep track of the PRINTABLE length of the line as  ***
 *** it is being built (well, sort of).                                ***
 *************************************************************************/

#include "less.h"

static char linebuf[1024];  /* Buffer which holds the current output line */
static char *curr;          /* Pointer into linebuf */
static int column;   /* Printable length, accounting for backspaces, etc. */

char    *line; /* Pointer to the current line. Usually points to linebuf. */

extern int sc_width, sc_height;

void    prewind() /*=====================================================*/
{                 /* Rewind line buffer.                                 */
    line = curr = linebuf;
    column = 0;
}

#define NEW_COLUMN(nc)  if ((nc) > sc_width+50) return(1); else column = (nc);

int     pappend(c) /*====================================================*/
register int    c; /* Append char to buffer, return !success.            */
{
    if (!c) {       /* Add zero to string */
        *curr = 0;
        return(0);
    }

  /* check if much buffer left */
    if (curr - linebuf > sizeof(linebuf) - 12) return(1);

  /* Used to expand tabs. Let console worry about that. May cause probs
   * if auto-wrap was on (which it isn't), and will frack the l_start
   * stuff a little. (Actually put out ^I at the moment). */

  /* Let the ESC codesd pass through OK. */

  /* Deal with ctrl-characters at the put_line level, one of the benefits
   * of which is that the high bit isn't required to flag carats */

  /* Ordinary character.  Just put it in the buffer */
    NEW_COLUMN(column+1);
    *curr++ = c;
    return(0);
}

LONG    forw_raw_line(curr_pos) /*=======================================*/
LONG    curr_pos;        /* Similar to forw_line(), but for "raw lines". */
{
register char   *p;
register int    c;
LONG            new_pos;

    if ((curr_pos == NULL_POSITION) || ch_seek(curr_pos) || ((c = ch_forw_get()) == EOF))
        return(NULL_POSITION);      /* Can't go forward */

    p = linebuf;

    for (;;) {
        if ((c == '\n') || (c == EOF)) {
            new_pos = ch_tell();
            break;
        }
        if (p >= &linebuf[sizeof(linebuf)-1]) {
      /* Overflowed the input buffer. Pretend the line ended here. */
            new_pos = ch_tell() - 1;
            break;
        }
        *p++ = c;
        c = ch_forw_get();
    }
    *p = 0;
    line = linebuf;
    return(new_pos);
}

LONG    back_raw_line(curr_pos) /*=======================================*/
LONG    curr_pos;               /* As above, but backwards.              */
{
register char   *p;
register int    c;
LONG            new_pos;

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

    p = &linebuf[sizeof(linebuf)];
    *(--p) = 0;

    for (;;) {
        c = ch_back_get();
        if (c == '\n') {    /* Newline ending previous line */
            new_pos = ch_tell() + 1;
            break;
        }
        if (c == EOF) {     /* Hit beginning of file */
            new_pos = 0;
            break;
        }
        if (p <= linebuf) { /* Overflowed the input buffer */
            new_pos = ch_tell() + 1;
            break;
        }
        *(--p) = c;
    }
    line = p;
    return(new_pos);
}
