forwback.c revision 60812
160812Sps/* $FreeBSD: head/contrib/less/forwback.c 60812 2000-05-23 05:51:17Z ps $ */ 260786Sps/* 360786Sps * Copyright (C) 1984-2000 Mark Nudelman 460786Sps * 560786Sps * You may distribute under the terms of either the GNU General Public 660786Sps * License or the Less License, as specified in the README file. 760786Sps * 860786Sps * For more information about less, or for information on how to 960786Sps * contact the author, see the README file. 1060786Sps */ 1160786Sps 1260786Sps 1360786Sps/* 1460786Sps * Primitives for displaying the file on the screen, 1560786Sps * scrolling either forward or backward. 1660786Sps */ 1760786Sps 1860786Sps#include "less.h" 1960786Sps#include "position.h" 2060786Sps 2160786Spspublic int hit_eof; /* Keeps track of how many times we hit end of file */ 2260786Spspublic int screen_trashed; 2360786Spspublic int squished; 2460786Spspublic int no_back_scroll = 0; 2560786Sps 2660786Spsextern int sigs; 2760786Spsextern int top_scroll; 2860786Spsextern int quiet; 2960786Spsextern int sc_width, sc_height; 3060786Spsextern int quit_at_eof; 3160812Spsextern int more_mode; 3260786Spsextern int plusoption; 3360786Spsextern int forw_scroll; 3460786Spsextern int back_scroll; 3560786Spsextern int ignore_eoi; 3660786Spsextern int clear_bg; 3760786Spsextern int final_attr; 3860786Sps#if TAGS 3960786Spsextern char *tagoption; 4060786Sps#endif 4160786Sps 4260786Sps/* 4360786Sps * Sound the bell to indicate user is trying to move past end of file. 4460786Sps */ 4560786Sps static void 4660786Spseof_bell() 4760786Sps{ 4860786Sps if (quiet == NOT_QUIET) 4960786Sps bell(); 5060786Sps else 5160786Sps vbell(); 5260786Sps} 5360786Sps 5460786Sps/* 5560786Sps * Check to see if the end of file is currently "displayed". 5660786Sps */ 5760786Sps static void 5860786Spseof_check() 5960786Sps{ 6060786Sps POSITION pos; 6160786Sps 6260786Sps if (ignore_eoi) 6360786Sps return; 6460786Sps if (ABORT_SIGS()) 6560786Sps return; 6660786Sps /* 6760786Sps * If the bottom line is empty, we are at EOF. 6860786Sps * If the bottom line ends at the file length, 6960786Sps * we must be just at EOF. 7060786Sps */ 7160786Sps pos = position(BOTTOM_PLUS_ONE); 7260786Sps if (pos == NULL_POSITION || pos == ch_length()) 7360786Sps hit_eof++; 7460786Sps} 7560786Sps 7660786Sps/* 7760786Sps * If the screen is "squished", repaint it. 7860786Sps * "Squished" means the first displayed line is not at the top 7960786Sps * of the screen; this can happen when we display a short file 8060786Sps * for the first time. 8160786Sps */ 8260786Sps static void 8360786Spssquish_check() 8460786Sps{ 8560786Sps if (!squished) 8660786Sps return; 8760786Sps squished = 0; 8860786Sps repaint(); 8960786Sps} 9060786Sps 9160786Sps/* 9260786Sps * Display n lines, scrolling forward, 9360786Sps * starting at position pos in the input file. 9460786Sps * "force" means display the n lines even if we hit end of file. 9560786Sps * "only_last" means display only the last screenful if n > screen size. 9660786Sps * "nblank" is the number of blank lines to draw before the first 9760786Sps * real line. If nblank > 0, the pos must be NULL_POSITION. 9860786Sps * The first real line after the blanks will start at ch_zero(). 9960786Sps */ 10060786Sps public void 10160786Spsforw(n, pos, force, only_last, nblank) 10260786Sps register int n; 10360786Sps POSITION pos; 10460786Sps int force; 10560786Sps int only_last; 10660786Sps int nblank; 10760786Sps{ 10860786Sps int eof = 0; 10960786Sps int nlines = 0; 11060786Sps int do_repaint; 11160786Sps static int first_time = 1; 11260786Sps 11360786Sps squish_check(); 11460786Sps 11560786Sps /* 11660786Sps * do_repaint tells us not to display anything till the end, 11760786Sps * then just repaint the entire screen. 11860786Sps * We repaint if we are supposed to display only the last 11960786Sps * screenful and the request is for more than a screenful. 12060786Sps * Also if the request exceeds the forward scroll limit 12160786Sps * (but not if the request is for exactly a screenful, since 12260786Sps * repainting itself involves scrolling forward a screenful). 12360786Sps */ 12460786Sps do_repaint = (only_last && n > sc_height-1) || 12560786Sps (forw_scroll >= 0 && n > forw_scroll && n != sc_height-1); 12660786Sps 12760786Sps if (!do_repaint) 12860786Sps { 12960786Sps /* 13060786Sps * Forget any current line shift we might have 13160786Sps * (from the last line of the previous screenful). 13260786Sps */ 13360786Sps extern int cshift; 13460786Sps cshift = 0; 13560786Sps 13660786Sps if (top_scroll && n >= sc_height - 1 && pos != ch_length()) 13760786Sps { 13860786Sps /* 13960786Sps * Start a new screen. 14060786Sps * {{ This is not really desirable if we happen 14160786Sps * to hit eof in the middle of this screen, 14260786Sps * but we don't yet know if that will happen. }} 14360786Sps */ 14460786Sps pos_clear(); 14560786Sps add_forw_pos(pos); 14660786Sps force = 1; 14760812Sps if (more_mode == 0) 14860812Sps { 14960812Sps if (top_scroll == OPT_ONPLUS || first_time) 15060812Sps clear(); 15160812Sps home(); 15260812Sps } 15360786Sps } else 15460786Sps { 15560786Sps clear_bot(); 15660786Sps } 15760786Sps 15860786Sps if (pos != position(BOTTOM_PLUS_ONE) || empty_screen()) 15960786Sps { 16060786Sps /* 16160786Sps * This is not contiguous with what is 16260786Sps * currently displayed. Clear the screen image 16360786Sps * (position table) and start a new screen. 16460786Sps */ 16560786Sps pos_clear(); 16660786Sps add_forw_pos(pos); 16760786Sps force = 1; 16860786Sps if (top_scroll) 16960786Sps { 17060786Sps if (top_scroll == OPT_ONPLUS) 17160786Sps clear(); 17260786Sps home(); 17360786Sps } else if (!first_time) 17460786Sps { 17560786Sps putstr("...skipping...\n"); 17660786Sps } 17760786Sps } 17860786Sps } 17960786Sps 18060786Sps while (--n >= 0) 18160786Sps { 18260786Sps /* 18360786Sps * Read the next line of input. 18460786Sps */ 18560786Sps if (nblank > 0) 18660786Sps { 18760786Sps /* 18860786Sps * Still drawing blanks; don't get a line 18960786Sps * from the file yet. 19060786Sps * If this is the last blank line, get ready to 19160786Sps * read a line starting at ch_zero() next time. 19260786Sps */ 19360786Sps if (--nblank == 0) 19460786Sps pos = ch_zero(); 19560786Sps } else 19660786Sps { 19760786Sps /* 19860786Sps * Get the next line from the file. 19960786Sps */ 20060786Sps pos = forw_line(pos); 20160786Sps if (pos == NULL_POSITION) 20260786Sps { 20360786Sps /* 20460786Sps * End of file: stop here unless the top line 20560786Sps * is still empty, or "force" is true. 20660786Sps * Even if force is true, stop when the last 20760786Sps * line in the file reaches the top of screen. 20860786Sps */ 20960786Sps eof = 1; 21060786Sps if (!force && position(TOP) != NULL_POSITION) 21160786Sps break; 21260786Sps if (!empty_lines(0, 0) && 21360786Sps !empty_lines(1, 1) && 21460786Sps empty_lines(2, sc_height-1)) 21560786Sps break; 21660786Sps } 21760786Sps } 21860786Sps /* 21960786Sps * Add the position of the next line to the position table. 22060786Sps * Display the current line on the screen. 22160786Sps */ 22260786Sps add_forw_pos(pos); 22360786Sps nlines++; 22460786Sps if (do_repaint) 22560786Sps continue; 22660786Sps /* 22760786Sps * If this is the first screen displayed and 22860786Sps * we hit an early EOF (i.e. before the requested 22960786Sps * number of lines), we "squish" the display down 23060786Sps * at the bottom of the screen. 23160786Sps * But don't do this if a + option or a -t option 23260786Sps * was given. These options can cause us to 23360786Sps * start the display after the beginning of the file, 23460786Sps * and it is not appropriate to squish in that case. 23560786Sps */ 23660786Sps if (first_time && pos == NULL_POSITION && !top_scroll && 23760786Sps#if TAGS 23860786Sps tagoption == NULL && 23960786Sps#endif 24060786Sps !plusoption) 24160786Sps { 24260786Sps squished = 1; 24360786Sps continue; 24460786Sps } 24560786Sps if (top_scroll == OPT_ON) 24660786Sps clear_eol(); 24760786Sps put_line(); 24860786Sps if (clear_bg && final_attr != AT_NORMAL) 24960786Sps { 25060786Sps /* 25160786Sps * Writing the last character on the last line 25260786Sps * of the display may have scrolled the screen. 25360786Sps * If we were in standout mode, clear_bg terminals 25460786Sps * will fill the new line with the standout color. 25560786Sps * Now we're in normal mode again, so clear the line. 25660786Sps */ 25760786Sps clear_eol(); 25860786Sps } 25960786Sps } 26060786Sps 26160786Sps if (ignore_eoi) 26260786Sps hit_eof = 0; 26360786Sps else if (eof && !ABORT_SIGS()) 26460786Sps hit_eof++; 26560786Sps else 26660786Sps eof_check(); 26760786Sps if (nlines == 0) 26860786Sps eof_bell(); 26960786Sps else if (do_repaint) 27060786Sps repaint(); 27160786Sps first_time = 0; 27260786Sps (void) currline(BOTTOM); 27360786Sps} 27460786Sps 27560786Sps/* 27660786Sps * Display n lines, scrolling backward. 27760786Sps */ 27860786Sps public void 27960786Spsback(n, pos, force, only_last) 28060786Sps register int n; 28160786Sps POSITION pos; 28260786Sps int force; 28360786Sps int only_last; 28460786Sps{ 28560786Sps int nlines = 0; 28660786Sps int do_repaint; 28760786Sps 28860786Sps squish_check(); 28960786Sps do_repaint = (n > get_back_scroll() || (only_last && n > sc_height-1)); 29060786Sps hit_eof = 0; 29160786Sps while (--n >= 0) 29260786Sps { 29360786Sps /* 29460786Sps * Get the previous line of input. 29560786Sps */ 29660786Sps pos = back_line(pos); 29760786Sps if (pos == NULL_POSITION) 29860786Sps { 29960786Sps /* 30060786Sps * Beginning of file: stop here unless "force" is true. 30160786Sps */ 30260786Sps if (!force) 30360786Sps break; 30460786Sps } 30560786Sps /* 30660786Sps * Add the position of the previous line to the position table. 30760786Sps * Display the line on the screen. 30860786Sps */ 30960786Sps add_back_pos(pos); 31060786Sps nlines++; 31160786Sps if (!do_repaint) 31260786Sps { 31360786Sps home(); 31460786Sps add_line(); 31560786Sps put_line(); 31660786Sps } 31760786Sps } 31860786Sps 31960786Sps eof_check(); 32060786Sps if (nlines == 0) 32160786Sps eof_bell(); 32260786Sps else if (do_repaint) 32360786Sps repaint(); 32460786Sps (void) currline(BOTTOM); 32560786Sps} 32660786Sps 32760786Sps/* 32860786Sps * Display n more lines, forward. 32960786Sps * Start just after the line currently displayed at the bottom of the screen. 33060786Sps */ 33160786Sps public void 33260786Spsforward(n, force, only_last) 33360786Sps int n; 33460786Sps int force; 33560786Sps int only_last; 33660786Sps{ 33760786Sps POSITION pos; 33860786Sps 33960786Sps if (quit_at_eof && hit_eof && !(ch_getflags() & CH_HELPFILE)) 34060786Sps { 34160786Sps /* 34260786Sps * If the -e flag is set and we're trying to go 34360786Sps * forward from end-of-file, go on to the next file. 34460786Sps */ 34560786Sps if (edit_next(1)) 34660786Sps quit(QUIT_OK); 34760786Sps return; 34860786Sps } 34960786Sps 35060786Sps pos = position(BOTTOM_PLUS_ONE); 35160786Sps if (pos == NULL_POSITION && (!force || empty_lines(2, sc_height-1))) 35260786Sps { 35360786Sps if (ignore_eoi) 35460786Sps { 35560786Sps /* 35660786Sps * ignore_eoi is to support A_F_FOREVER. 35760786Sps * Back up until there is a line at the bottom 35860786Sps * of the screen. 35960786Sps */ 36060786Sps if (empty_screen()) 36160786Sps pos = ch_zero(); 36260786Sps else 36360786Sps { 36460786Sps do 36560786Sps { 36660786Sps back(1, position(TOP), 1, 0); 36760786Sps pos = position(BOTTOM_PLUS_ONE); 36860786Sps } while (pos == NULL_POSITION); 36960786Sps } 37060786Sps } else 37160786Sps { 37260786Sps eof_bell(); 37360786Sps hit_eof++; 37460786Sps return; 37560786Sps } 37660786Sps } 37760786Sps forw(n, pos, force, only_last, 0); 37860786Sps} 37960786Sps 38060786Sps/* 38160786Sps * Display n more lines, backward. 38260786Sps * Start just before the line currently displayed at the top of the screen. 38360786Sps */ 38460786Sps public void 38560786Spsbackward(n, force, only_last) 38660786Sps int n; 38760786Sps int force; 38860786Sps int only_last; 38960786Sps{ 39060786Sps POSITION pos; 39160786Sps 39260786Sps pos = position(TOP); 39360786Sps if (pos == NULL_POSITION && (!force || position(BOTTOM) == 0)) 39460786Sps { 39560786Sps eof_bell(); 39660786Sps return; 39760786Sps } 39860786Sps back(n, pos, force, only_last); 39960786Sps} 40060786Sps 40160786Sps/* 40260786Sps * Get the backwards scroll limit. 40360786Sps * Must call this function instead of just using the value of 40460786Sps * back_scroll, because the default case depends on sc_height and 40560786Sps * top_scroll, as well as back_scroll. 40660786Sps */ 40760786Sps public int 40860786Spsget_back_scroll() 40960786Sps{ 41060786Sps if (no_back_scroll) 41160786Sps return (0); 41260786Sps if (back_scroll >= 0) 41360786Sps return (back_scroll); 41460786Sps if (top_scroll) 41560786Sps return (sc_height - 2); 41660786Sps return (10000); /* infinity */ 41760786Sps} 418