home *** CD-ROM | disk | FTP | other *** search
- /*************************************************************************
- *** prim.c (JJB TEMPLAR) ***
- *** Date modifications begun: 7/8/89. ***
- *** Last modified: 27/8/89. ***
- *************************************************************************/
- /*** Primitives for displaying the file on the screen. ***
- *************************************************************************/
-
- #include "less.h"
- #include "position.h"
- #include "screen.h"
-
- int hit_eof; /* Keeps track of how many times we hit end of file */
-
- extern int quiet;
- extern int top_scroll;
- extern int back_scroll;
- extern int sc_height;
- extern char *line;
- extern int page_break;
-
- #define eof_bell() bell()
-
- void prepaint(LONG);
-
- static void eof_check() /*===============================================*/
- { /* Check if EOF displayed. */
- LONG pos;
-
- /* If the bottom line is empty, we are at EOF.
- If the bottom line ends at the file length, we must be just at EOF. */
- pos = position(BOTTOM_PLUS_ONE);
- if (((pos == NULL_POSITION) && !page_break) || (pos == ch_length()))
- hit_eof++;
- }
-
- static void forw(n, pos, force, only_last) /*============================*/
- register int n; /* Display n lines, scrolling forward. */
- LONG pos; /* Starting from position pos in the file. */
- int force; /* Display lines even if hit eof. */
- int only_last; /* Display only last screenful if n > screen size. */
- {
- int eof = 0;
- int nlines = 0;
- int repaint_flag,top_flag = 0;
-
- repaint_flag = (only_last && (n > sc_height-1));
-
- if (!repaint_flag) {
- if (top_scroll && (n >= sc_height - 1)) {
- clear(); /* From top of screen */
- home();
- force = 1;
- top_flag = 1; /* Don't precede top line with '\n' */
- }
- else { /* Or from bottom left */
- lower_left();
- }
-
- if (pos != position(BOTTOM_PLUS_ONE)) {
- /* This is not contiguous with what is currently displayed.
- Clear the screen image (position table) and start a new screen. */
- pos_clear();
- add_forw_pos(pos);
- force = 1;
- if (top_scroll) {
- clear();
- home();
- top_flag = 1;
- }
- else puts("...skipping...\n");
- }
- }
-
- while (--n >= 0) {
- /* Read the next line of input. */
- pos = forw_line(pos);
- if (pos == NULL_POSITION) {
- /* End of file: stop here unless the top line
- is still empty, or "force" is true. */
- if (!page_break) eof = 1;
- if (!force && (position(TOP) != NULL_POSITION)) break;
- line = NULL;
- }
- /* Add the position of the next line to the position table.
- Display the current line on the screen. */
- add_forw_pos(pos);
- nlines++;
- if (!repaint_flag) {
- if (top_flag) top_flag = 0;
- else putc('\n');
- put_line();
- }
- }
-
- if (eof) hit_eof++;
- else eof_check();
- if (!nlines) eof_bell();
- else if (repaint_flag) repaint();
- page_break = 0;
- }
-
- static void back(n, pos, force, only_last) /*============================*/
- register int n; /* As above, but backward */
- LONG pos;
- int force;
- int only_last;
- {
- int nlines = 0;
- int repaint_flag;
- int tempn = n;
-
- repaint_flag = ((n > back_scroll) || (only_last && (n > sc_height-1)));
- hit_eof = 0;
- while (--n >= 0) {
- /* Get the previous line of input. */
- pos = back_line(pos);
- if (pos == NULL_POSITION) {
- /* Beginning of file: stop here unless "force" is true. */
- if (!force) break;
- line = NULL;
- }
- if (page_break && (n == tempn - 1)) page_break = 0;
- /* Add the position of the previous line to the position table.
- Display the line on the screen. */
- add_back_pos(pos);
- nlines++;
- if (!repaint_flag && !page_break) {
- home();
- add_line();
- put_line(); putc('\n');
- }
- }
-
- if (page_break) {
- page_break = 0;
- pos = forw_line(pos);
- page_break = 0;
- set_top_pos(pos); /* Patched together with a nappy pin and */
- repaint(pos); /* chewing gum... Very wierd this. */
- }
- else {
- eof_check();
- if (!nlines) eof_bell();
- else if (repaint_flag) repaint();
- }
- }
-
- void forward(n, only_last) /*=========================================*/
- int n; /* Display n more lines, forward. */
- int only_last;
- {
- LONG pos;
-
- pos = position(BOTTOM_PLUS_ONE);
- if (pos == NULL_POSITION) {
- eof_bell();
- hit_eof++;
- return;
- }
- forw(n, pos, 0, only_last);
- }
-
- void backward(n, only_last) /*========================================*/
- int n; /* Display n more lines, backward. */
- int only_last;
- {
- LONG pos;
-
- pos = position(TOP);
- if (pos == NULL_POSITION) {
- /* This will almost never happen,
- because the top line is almost never empty. */
- eof_bell();
- return;
- }
- back(n, pos, 0, only_last);
- }
-
- static void prepaint(pos) /*=============================================*/
- LONG pos; /* Repaint, starting from a specified pos. */
- {
- hit_eof = 0;
- forw(sc_height-1, pos, 0, 0);
- }
-
- void repaint() /*=====================================================*/
- { /* Start at line currently at the top of screen and redisplay screen. */
- register int temp;
- temp = top_scroll;
- top_scroll = 1;
- prepaint(position(TOP));
- top_scroll = temp;
- }
-
- void jump_forw() /*===================================================*/
- {
- LONG pos;
-
- /* Jump to the end of the file. It is more convenient to paint the screen
- * backward, from the end of the file toward the beginning. */
- end_seek();
- pos = ch_tell();
- clear();
- pos_clear();
- add_back_pos(pos);
- back(sc_height - 1, pos, 0, 0);
- }
-
- void jump_back(n) /*==================================================*/
- register int n; /* Jump to line n in file. */
- {
- register int c;
-
- /* This is done the slow way, by starting at the beginning
- of the file and counting newlines. */
- if (ch_seek(0)) {
- /* Probably a pipe with beginning of file no longer buffered. */
- error("Cannot get to beginning of file",0);
- return;
- }
-
- /* Start counting lines. */
- while (--n > 0) {
- while ((c = ch_forw_get()) != '\n')
- if (c == EOF) {
- error("File is not that long",0);
- /* {{ Maybe tell him how long it is? }} */
- return;
- }
- }
-
- /* Finally found the place to start.
- Clear and redisplay the screen from there.
- {{ We *could* figure out if the new position is close enough to just
- scroll there without clearing the screen, but it's not worth it. }} */
- prepaint(ch_tell());
- }
-
- void jump_percent() /*================================================*/
- { /* Jump a %age into the file. */
- static int percent;
- LONG pos,len;
-
- if (!(r_int("Percentage",&percent,3))) return; /* 2 digits max */
- if (percent < 0) percent = 0;
-
- if ((len = ch_length()) == NULL_POSITION) {
- error("Don't know length of file",0);
- return;
- }
- pos = (percent * len) / 100;
- jump_loc(pos);
- setbar(0);
- }
-
- void jump_loc(pos) /*=================================================*/
- LONG pos;
- {
- register int c;
- register int nline;
- LONG tpos;
-
- /* See if the desired line is BEFORE the currently displayed screen.
- If so, see if it is close enough to scroll backwards to it. */
- tpos = position(TOP);
- if (pos < tpos) {
- for (nline = 1; nline <= back_scroll; nline++) {
- tpos = back_line(tpos);
- if (tpos == NULL_POSITION || tpos <= pos) {
- back(nline, position(TOP), 1, 0);
- return;
- }
- }
- }
- else if ((nline = onscreen(pos)) >= 0) {
- /* The line is currently displayed. Just scroll there. */
- forw(nline, position(BOTTOM_PLUS_ONE), 1, 0);
- return;
- }
-
- /* Line is not on screen. Back up to the beginning of the current line. */
- if (ch_seek(pos)) {
- error("Cannot seek to that position",0);
- return;
- }
- while ((c = ch_back_get()) != '\n' && c != EOF);
- if (c == '\n') ch_forw_get();
-
- /* Clear and paint the screen. */
- prepaint(ch_tell());
- }
-