160812Sps/* $FreeBSD$ */ 260786Sps/* 3240121Sdelphij * Copyright (C) 1984-2012 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 * 8240121Sdelphij * For more information, see the README file. 960786Sps */ 1060786Sps 1160786Sps 1260786Sps/* 1360786Sps * Primitives for displaying the file on the screen, 1460786Sps * scrolling either forward or backward. 1560786Sps */ 1660786Sps 1760786Sps#include "less.h" 1860786Sps#include "position.h" 1960786Sps 2060786Spspublic int screen_trashed; 2160786Spspublic int squished; 2260786Spspublic int no_back_scroll = 0; 23170259Sdelphijpublic int forw_prompt; 2460786Sps 2560786Spsextern int sigs; 2660786Spsextern int top_scroll; 2760786Spsextern int quiet; 2860786Spsextern int sc_width, sc_height; 29170259Sdelphijextern int less_is_more; 3060786Spsextern int plusoption; 3160786Spsextern int forw_scroll; 3260786Spsextern int back_scroll; 3360786Spsextern int ignore_eoi; 3460786Spsextern int clear_bg; 3560786Spsextern int final_attr; 36170259Sdelphijextern int oldbot; 3760786Sps#if TAGS 3860786Spsextern char *tagoption; 3960786Sps#endif 4060786Sps 4160786Sps/* 4260786Sps * Sound the bell to indicate user is trying to move past end of file. 4360786Sps */ 4460786Sps static void 4560786Spseof_bell() 4660786Sps{ 4760786Sps if (quiet == NOT_QUIET) 4860786Sps bell(); 4960786Sps else 5060786Sps vbell(); 5160786Sps} 5260786Sps 5360786Sps/* 54191930Sdelphij * Check to see if the end of file is currently displayed. 5560786Sps */ 56191930Sdelphij public int 57191930Sdelphijeof_displayed() 5860786Sps{ 5960786Sps POSITION pos; 6060786Sps 6160786Sps if (ignore_eoi) 62191930Sdelphij return (0); 63191930Sdelphij 64191930Sdelphij if (ch_length() == NULL_POSITION) 65191930Sdelphij /* 66191930Sdelphij * If the file length is not known, 67191930Sdelphij * we can't possibly be displaying EOF. 68191930Sdelphij */ 69191930Sdelphij return (0); 70191930Sdelphij 7160786Sps /* 7260786Sps * If the bottom line is empty, we are at EOF. 7360786Sps * If the bottom line ends at the file length, 7460786Sps * we must be just at EOF. 7560786Sps */ 7660786Sps pos = position(BOTTOM_PLUS_ONE); 77191930Sdelphij return (pos == NULL_POSITION || pos == ch_length()); 7860786Sps} 7960786Sps 8060786Sps/* 81191930Sdelphij * Check to see if the entire file is currently displayed. 82191930Sdelphij */ 83191930Sdelphij public int 84191930Sdelphijentire_file_displayed() 85191930Sdelphij{ 86191930Sdelphij POSITION pos; 87191930Sdelphij 88191930Sdelphij /* Make sure last line of file is displayed. */ 89191930Sdelphij if (!eof_displayed()) 90191930Sdelphij return (0); 91191930Sdelphij 92191930Sdelphij /* Make sure first line of file is displayed. */ 93191930Sdelphij pos = position(0); 94191930Sdelphij return (pos == NULL_POSITION || pos == 0); 95191930Sdelphij} 96191930Sdelphij 97191930Sdelphij/* 9860786Sps * If the screen is "squished", repaint it. 9960786Sps * "Squished" means the first displayed line is not at the top 10060786Sps * of the screen; this can happen when we display a short file 10160786Sps * for the first time. 10260786Sps */ 103170259Sdelphij public void 10460786Spssquish_check() 10560786Sps{ 10660786Sps if (!squished) 10760786Sps return; 10860786Sps squished = 0; 10960786Sps repaint(); 11060786Sps} 11160786Sps 11260786Sps/* 11360786Sps * Display n lines, scrolling forward, 11460786Sps * starting at position pos in the input file. 11560786Sps * "force" means display the n lines even if we hit end of file. 11660786Sps * "only_last" means display only the last screenful if n > screen size. 11760786Sps * "nblank" is the number of blank lines to draw before the first 11860786Sps * real line. If nblank > 0, the pos must be NULL_POSITION. 11960786Sps * The first real line after the blanks will start at ch_zero(). 12060786Sps */ 12160786Sps public void 12260786Spsforw(n, pos, force, only_last, nblank) 12360786Sps register int n; 12460786Sps POSITION pos; 12560786Sps int force; 12660786Sps int only_last; 12760786Sps int nblank; 12860786Sps{ 12960786Sps int eof = 0; 13060786Sps int nlines = 0; 13160786Sps int do_repaint; 13260786Sps static int first_time = 1; 13360786Sps 13460786Sps squish_check(); 13560786Sps 13660786Sps /* 13760786Sps * do_repaint tells us not to display anything till the end, 13860786Sps * then just repaint the entire screen. 13960786Sps * We repaint if we are supposed to display only the last 14060786Sps * screenful and the request is for more than a screenful. 14160786Sps * Also if the request exceeds the forward scroll limit 14260786Sps * (but not if the request is for exactly a screenful, since 14360786Sps * repainting itself involves scrolling forward a screenful). 14460786Sps */ 14560786Sps do_repaint = (only_last && n > sc_height-1) || 14660786Sps (forw_scroll >= 0 && n > forw_scroll && n != sc_height-1); 14760786Sps 14860786Sps if (!do_repaint) 14960786Sps { 15060786Sps if (top_scroll && n >= sc_height - 1 && pos != ch_length()) 15160786Sps { 15260786Sps /* 15360786Sps * Start a new screen. 15460786Sps * {{ This is not really desirable if we happen 15560786Sps * to hit eof in the middle of this screen, 15660786Sps * but we don't yet know if that will happen. }} 15760786Sps */ 15860786Sps pos_clear(); 15960786Sps add_forw_pos(pos); 16060786Sps force = 1; 161170259Sdelphij if (less_is_more == 0) { 162170259Sdelphij clear(); 16360812Sps home(); 16460812Sps } 16560786Sps } 16660786Sps 16760786Sps if (pos != position(BOTTOM_PLUS_ONE) || empty_screen()) 16860786Sps { 16960786Sps /* 17060786Sps * This is not contiguous with what is 17160786Sps * currently displayed. Clear the screen image 17260786Sps * (position table) and start a new screen. 17360786Sps */ 17460786Sps pos_clear(); 17560786Sps add_forw_pos(pos); 17660786Sps force = 1; 17760786Sps if (top_scroll) 17860786Sps { 179170259Sdelphij clear(); 18060786Sps home(); 18160786Sps } else if (!first_time) 18260786Sps { 18360786Sps putstr("...skipping...\n"); 18460786Sps } 18560786Sps } 18660786Sps } 18760786Sps 18860786Sps while (--n >= 0) 18960786Sps { 19060786Sps /* 19160786Sps * Read the next line of input. 19260786Sps */ 19360786Sps if (nblank > 0) 19460786Sps { 19560786Sps /* 19660786Sps * Still drawing blanks; don't get a line 19760786Sps * from the file yet. 19860786Sps * If this is the last blank line, get ready to 19960786Sps * read a line starting at ch_zero() next time. 20060786Sps */ 20160786Sps if (--nblank == 0) 20260786Sps pos = ch_zero(); 20360786Sps } else 20460786Sps { 20560786Sps /* 20660786Sps * Get the next line from the file. 20760786Sps */ 20860786Sps pos = forw_line(pos); 20960786Sps if (pos == NULL_POSITION) 21060786Sps { 21160786Sps /* 21260786Sps * End of file: stop here unless the top line 21360786Sps * is still empty, or "force" is true. 21460786Sps * Even if force is true, stop when the last 21560786Sps * line in the file reaches the top of screen. 21660786Sps */ 21760786Sps eof = 1; 21860786Sps if (!force && position(TOP) != NULL_POSITION) 21960786Sps break; 22060786Sps if (!empty_lines(0, 0) && 22160786Sps !empty_lines(1, 1) && 22260786Sps empty_lines(2, sc_height-1)) 22360786Sps break; 22460786Sps } 22560786Sps } 22660786Sps /* 22760786Sps * Add the position of the next line to the position table. 22860786Sps * Display the current line on the screen. 22960786Sps */ 23060786Sps add_forw_pos(pos); 23160786Sps nlines++; 23260786Sps if (do_repaint) 23360786Sps continue; 23460786Sps /* 23560786Sps * If this is the first screen displayed and 23660786Sps * we hit an early EOF (i.e. before the requested 23760786Sps * number of lines), we "squish" the display down 23860786Sps * at the bottom of the screen. 23960786Sps * But don't do this if a + option or a -t option 24060786Sps * was given. These options can cause us to 24160786Sps * start the display after the beginning of the file, 24260786Sps * and it is not appropriate to squish in that case. 24360786Sps */ 244170259Sdelphij if ((first_time || less_is_more) && 24560816Sps pos == NULL_POSITION && !top_scroll && 24660786Sps#if TAGS 24760786Sps tagoption == NULL && 24860786Sps#endif 24960786Sps !plusoption) 25060786Sps { 25160786Sps squished = 1; 25260786Sps continue; 25360786Sps } 25460786Sps put_line(); 255170259Sdelphij#if 0 256170259Sdelphij /* {{ 257170259Sdelphij * Can't call clear_eol here. The cursor might be at end of line 258170259Sdelphij * on an ignaw terminal, so clear_eol would clear the last char 259170259Sdelphij * of the current line instead of all of the next line. 260170259Sdelphij * If we really need to do this on clear_bg terminals, we need 261170259Sdelphij * to find a better way. 262170259Sdelphij * }} 263170259Sdelphij */ 264161478Sdelphij if (clear_bg && apply_at_specials(final_attr) != AT_NORMAL) 26560786Sps { 26660786Sps /* 26760786Sps * Writing the last character on the last line 26860786Sps * of the display may have scrolled the screen. 26960786Sps * If we were in standout mode, clear_bg terminals 27060786Sps * will fill the new line with the standout color. 27160786Sps * Now we're in normal mode again, so clear the line. 27260786Sps */ 27360786Sps clear_eol(); 27460786Sps } 275170259Sdelphij#endif 276170259Sdelphij forw_prompt = 1; 27760786Sps } 27860786Sps 27960786Sps if (nlines == 0) 28060786Sps eof_bell(); 28160786Sps else if (do_repaint) 28260786Sps repaint(); 28360786Sps first_time = 0; 28460786Sps (void) currline(BOTTOM); 28560786Sps} 28660786Sps 28760786Sps/* 28860786Sps * Display n lines, scrolling backward. 28960786Sps */ 29060786Sps public void 29160786Spsback(n, pos, force, only_last) 29260786Sps register int n; 29360786Sps POSITION pos; 29460786Sps int force; 29560786Sps int only_last; 29660786Sps{ 29760786Sps int nlines = 0; 29860786Sps int do_repaint; 29960786Sps 30060786Sps squish_check(); 30160786Sps do_repaint = (n > get_back_scroll() || (only_last && n > sc_height-1)); 30260786Sps while (--n >= 0) 30360786Sps { 30460786Sps /* 30560786Sps * Get the previous line of input. 30660786Sps */ 30760786Sps pos = back_line(pos); 30860786Sps if (pos == NULL_POSITION) 30960786Sps { 31060786Sps /* 31160786Sps * Beginning of file: stop here unless "force" is true. 31260786Sps */ 31360786Sps if (!force) 31460786Sps break; 31560786Sps } 31660786Sps /* 31760786Sps * Add the position of the previous line to the position table. 31860786Sps * Display the line on the screen. 31960786Sps */ 32060786Sps add_back_pos(pos); 32160786Sps nlines++; 32260786Sps if (!do_repaint) 32360786Sps { 32460786Sps home(); 32560786Sps add_line(); 32660786Sps put_line(); 32760786Sps } 32860786Sps } 32960786Sps 33060786Sps if (nlines == 0) 33160786Sps eof_bell(); 33260786Sps else if (do_repaint) 33360786Sps repaint(); 334170259Sdelphij else if (!oldbot) 335170259Sdelphij lower_left(); 33660786Sps (void) currline(BOTTOM); 33760786Sps} 33860786Sps 33960786Sps/* 34060786Sps * Display n more lines, forward. 34160786Sps * Start just after the line currently displayed at the bottom of the screen. 34260786Sps */ 34360786Sps public void 34460786Spsforward(n, force, only_last) 34560786Sps int n; 34660786Sps int force; 34760786Sps int only_last; 34860786Sps{ 34960786Sps POSITION pos; 35060786Sps 351191930Sdelphij if (get_quit_at_eof() && eof_displayed() && !(ch_getflags() & CH_HELPFILE)) 35260786Sps { 35360786Sps /* 35460786Sps * If the -e flag is set and we're trying to go 35560786Sps * forward from end-of-file, go on to the next file. 35660786Sps */ 35760786Sps if (edit_next(1)) 35860786Sps quit(QUIT_OK); 35960786Sps return; 36060786Sps } 36160786Sps 36260786Sps pos = position(BOTTOM_PLUS_ONE); 36360786Sps if (pos == NULL_POSITION && (!force || empty_lines(2, sc_height-1))) 36460786Sps { 36560786Sps if (ignore_eoi) 36660786Sps { 36760786Sps /* 36860786Sps * ignore_eoi is to support A_F_FOREVER. 36960786Sps * Back up until there is a line at the bottom 37060786Sps * of the screen. 37160786Sps */ 37260786Sps if (empty_screen()) 37360786Sps pos = ch_zero(); 37460786Sps else 37560786Sps { 37660786Sps do 37760786Sps { 37860786Sps back(1, position(TOP), 1, 0); 37960786Sps pos = position(BOTTOM_PLUS_ONE); 38060786Sps } while (pos == NULL_POSITION); 38160786Sps } 38260786Sps } else 38360786Sps { 38460786Sps eof_bell(); 38560786Sps return; 38660786Sps } 38760786Sps } 38860786Sps forw(n, pos, force, only_last, 0); 38960786Sps} 39060786Sps 39160786Sps/* 39260786Sps * Display n more lines, backward. 39360786Sps * Start just before the line currently displayed at the top of the screen. 39460786Sps */ 39560786Sps public void 39660786Spsbackward(n, force, only_last) 39760786Sps int n; 39860786Sps int force; 39960786Sps int only_last; 40060786Sps{ 40160786Sps POSITION pos; 40260786Sps 40360786Sps pos = position(TOP); 40460786Sps if (pos == NULL_POSITION && (!force || position(BOTTOM) == 0)) 40560786Sps { 40660786Sps eof_bell(); 40760786Sps return; 40860786Sps } 40960786Sps back(n, pos, force, only_last); 41060786Sps} 41160786Sps 41260786Sps/* 41360786Sps * Get the backwards scroll limit. 41460786Sps * Must call this function instead of just using the value of 41560786Sps * back_scroll, because the default case depends on sc_height and 41660786Sps * top_scroll, as well as back_scroll. 41760786Sps */ 41860786Sps public int 41960786Spsget_back_scroll() 42060786Sps{ 42160786Sps if (no_back_scroll) 42260786Sps return (0); 42360786Sps if (back_scroll >= 0) 42460786Sps return (back_scroll); 42560786Sps if (top_scroll) 42660786Sps return (sc_height - 2); 42760786Sps return (10000); /* infinity */ 42860786Sps} 429