/************************************************************************* *** 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()); }