160812Sps/* $FreeBSD: stable/10/contrib/less/forwback.c 330571 2018-03-07 06:39:00Z delphij $ */ 2238730Sdelphij/* 3330571Sdelphij * Copyright (C) 1984-2017 Mark Nudelman 4238730Sdelphij * 5238730Sdelphij * You may distribute under the terms of either the GNU General Public 6238730Sdelphij * License or the Less License, as specified in the README file. 7238730Sdelphij * 8238730Sdelphij * For more information, see the README file. 9238730Sdelphij */ 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; 24294286Sdelphijpublic int same_pos_bell = 1; 2560786Sps 2660786Spsextern int sigs; 2760786Spsextern int top_scroll; 2860786Spsextern int quiet; 2960786Spsextern int sc_width, sc_height; 30170259Sdelphijextern int less_is_more; 3160786Spsextern int plusoption; 3260786Spsextern int forw_scroll; 3360786Spsextern int back_scroll; 3460786Spsextern int ignore_eoi; 3560786Spsextern int clear_bg; 3660786Spsextern int final_attr; 37170259Sdelphijextern int oldbot; 38294286Sdelphij#if HILITE_SEARCH 39294286Sdelphijextern int size_linebuf; 40294286Sdelphijextern int hilite_search; 41294286Sdelphijextern int status_col; 42294286Sdelphij#endif 4360786Sps#if TAGS 4460786Spsextern char *tagoption; 4560786Sps#endif 4660786Sps 4760786Sps/* 4860786Sps * Sound the bell to indicate user is trying to move past end of file. 4960786Sps */ 5060786Sps static void 5160786Spseof_bell() 5260786Sps{ 5360786Sps if (quiet == NOT_QUIET) 5460786Sps bell(); 5560786Sps else 5660786Sps vbell(); 5760786Sps} 5860786Sps 5960786Sps/* 60191930Sdelphij * Check to see if the end of file is currently displayed. 6160786Sps */ 62191930Sdelphij public int 63191930Sdelphijeof_displayed() 6460786Sps{ 6560786Sps POSITION pos; 6660786Sps 6760786Sps if (ignore_eoi) 68191930Sdelphij return (0); 69191930Sdelphij 70191930Sdelphij if (ch_length() == NULL_POSITION) 71191930Sdelphij /* 72191930Sdelphij * If the file length is not known, 73191930Sdelphij * we can't possibly be displaying EOF. 74191930Sdelphij */ 75191930Sdelphij return (0); 76191930Sdelphij 7760786Sps /* 7860786Sps * If the bottom line is empty, we are at EOF. 7960786Sps * If the bottom line ends at the file length, 8060786Sps * we must be just at EOF. 8160786Sps */ 8260786Sps pos = position(BOTTOM_PLUS_ONE); 83191930Sdelphij return (pos == NULL_POSITION || pos == ch_length()); 8460786Sps} 8560786Sps 8660786Sps/* 87191930Sdelphij * Check to see if the entire file is currently displayed. 88191930Sdelphij */ 89191930Sdelphij public int 90191930Sdelphijentire_file_displayed() 91191930Sdelphij{ 92191930Sdelphij POSITION pos; 93191930Sdelphij 94191930Sdelphij /* Make sure last line of file is displayed. */ 95191930Sdelphij if (!eof_displayed()) 96191930Sdelphij return (0); 97191930Sdelphij 98191930Sdelphij /* Make sure first line of file is displayed. */ 99191930Sdelphij pos = position(0); 100191930Sdelphij return (pos == NULL_POSITION || pos == 0); 101191930Sdelphij} 102191930Sdelphij 103191930Sdelphij/* 10460786Sps * If the screen is "squished", repaint it. 10560786Sps * "Squished" means the first displayed line is not at the top 10660786Sps * of the screen; this can happen when we display a short file 10760786Sps * for the first time. 10860786Sps */ 109170259Sdelphij public void 11060786Spssquish_check() 11160786Sps{ 11260786Sps if (!squished) 11360786Sps return; 11460786Sps squished = 0; 11560786Sps repaint(); 11660786Sps} 11760786Sps 11860786Sps/* 11960786Sps * Display n lines, scrolling forward, 12060786Sps * starting at position pos in the input file. 12160786Sps * "force" means display the n lines even if we hit end of file. 12260786Sps * "only_last" means display only the last screenful if n > screen size. 12360786Sps * "nblank" is the number of blank lines to draw before the first 12460786Sps * real line. If nblank > 0, the pos must be NULL_POSITION. 12560786Sps * The first real line after the blanks will start at ch_zero(). 12660786Sps */ 12760786Sps public void 12860786Spsforw(n, pos, force, only_last, nblank) 129330571Sdelphij int n; 13060786Sps POSITION pos; 13160786Sps int force; 13260786Sps int only_last; 13360786Sps int nblank; 13460786Sps{ 13560786Sps int nlines = 0; 13660786Sps int do_repaint; 13760786Sps static int first_time = 1; 13860786Sps 13960786Sps squish_check(); 14060786Sps 14160786Sps /* 14260786Sps * do_repaint tells us not to display anything till the end, 14360786Sps * then just repaint the entire screen. 14460786Sps * We repaint if we are supposed to display only the last 14560786Sps * screenful and the request is for more than a screenful. 14660786Sps * Also if the request exceeds the forward scroll limit 14760786Sps * (but not if the request is for exactly a screenful, since 14860786Sps * repainting itself involves scrolling forward a screenful). 14960786Sps */ 15060786Sps do_repaint = (only_last && n > sc_height-1) || 15160786Sps (forw_scroll >= 0 && n > forw_scroll && n != sc_height-1); 15260786Sps 153294286Sdelphij#if HILITE_SEARCH 154294286Sdelphij if (hilite_search == OPT_ONPLUS || is_filtering() || status_col) { 155294286Sdelphij prep_hilite(pos, pos + 4*size_linebuf, ignore_eoi ? 1 : -1); 156294286Sdelphij pos = next_unfiltered(pos); 157294286Sdelphij } 158294286Sdelphij#endif 159294286Sdelphij 16060786Sps if (!do_repaint) 16160786Sps { 16260786Sps if (top_scroll && n >= sc_height - 1 && pos != ch_length()) 16360786Sps { 16460786Sps /* 16560786Sps * Start a new screen. 16660786Sps * {{ This is not really desirable if we happen 16760786Sps * to hit eof in the middle of this screen, 16860786Sps * but we don't yet know if that will happen. }} 16960786Sps */ 17060786Sps pos_clear(); 17160786Sps add_forw_pos(pos); 17260786Sps force = 1; 173170259Sdelphij if (less_is_more == 0) { 174170259Sdelphij clear(); 17560812Sps home(); 17660812Sps } 17760786Sps } 17860786Sps 17960786Sps if (pos != position(BOTTOM_PLUS_ONE) || empty_screen()) 18060786Sps { 18160786Sps /* 18260786Sps * This is not contiguous with what is 18360786Sps * currently displayed. Clear the screen image 18460786Sps * (position table) and start a new screen. 18560786Sps */ 18660786Sps pos_clear(); 18760786Sps add_forw_pos(pos); 18860786Sps force = 1; 18960786Sps if (top_scroll) 19060786Sps { 191170259Sdelphij clear(); 19260786Sps home(); 19360786Sps } else if (!first_time) 19460786Sps { 19560786Sps putstr("...skipping...\n"); 19660786Sps } 19760786Sps } 19860786Sps } 19960786Sps 20060786Sps while (--n >= 0) 20160786Sps { 20260786Sps /* 20360786Sps * Read the next line of input. 20460786Sps */ 20560786Sps if (nblank > 0) 20660786Sps { 20760786Sps /* 20860786Sps * Still drawing blanks; don't get a line 20960786Sps * from the file yet. 21060786Sps * If this is the last blank line, get ready to 21160786Sps * read a line starting at ch_zero() next time. 21260786Sps */ 21360786Sps if (--nblank == 0) 21460786Sps pos = ch_zero(); 21560786Sps } else 21660786Sps { 21760786Sps /* 21860786Sps * Get the next line from the file. 21960786Sps */ 22060786Sps pos = forw_line(pos); 221294286Sdelphij#if HILITE_SEARCH 222294286Sdelphij pos = next_unfiltered(pos); 223294286Sdelphij#endif 22460786Sps if (pos == NULL_POSITION) 22560786Sps { 22660786Sps /* 22760786Sps * End of file: stop here unless the top line 22860786Sps * is still empty, or "force" is true. 22960786Sps * Even if force is true, stop when the last 23060786Sps * line in the file reaches the top of screen. 23160786Sps */ 23260786Sps if (!force && position(TOP) != NULL_POSITION) 23360786Sps break; 23460786Sps if (!empty_lines(0, 0) && 23560786Sps !empty_lines(1, 1) && 23660786Sps empty_lines(2, sc_height-1)) 23760786Sps break; 23860786Sps } 23960786Sps } 24060786Sps /* 24160786Sps * Add the position of the next line to the position table. 24260786Sps * Display the current line on the screen. 24360786Sps */ 24460786Sps add_forw_pos(pos); 24560786Sps nlines++; 24660786Sps if (do_repaint) 24760786Sps continue; 24860786Sps /* 24960786Sps * If this is the first screen displayed and 25060786Sps * we hit an early EOF (i.e. before the requested 25160786Sps * number of lines), we "squish" the display down 25260786Sps * at the bottom of the screen. 25360786Sps * But don't do this if a + option or a -t option 25460786Sps * was given. These options can cause us to 25560786Sps * start the display after the beginning of the file, 25660786Sps * and it is not appropriate to squish in that case. 25760786Sps */ 258170259Sdelphij if ((first_time || less_is_more) && 25960816Sps pos == NULL_POSITION && !top_scroll && 26060786Sps#if TAGS 26160786Sps tagoption == NULL && 26260786Sps#endif 26360786Sps !plusoption) 26460786Sps { 26560786Sps squished = 1; 26660786Sps continue; 26760786Sps } 26860786Sps put_line(); 269170259Sdelphij#if 0 270170259Sdelphij /* {{ 271170259Sdelphij * Can't call clear_eol here. The cursor might be at end of line 272170259Sdelphij * on an ignaw terminal, so clear_eol would clear the last char 273170259Sdelphij * of the current line instead of all of the next line. 274170259Sdelphij * If we really need to do this on clear_bg terminals, we need 275170259Sdelphij * to find a better way. 276170259Sdelphij * }} 277170259Sdelphij */ 278161478Sdelphij if (clear_bg && apply_at_specials(final_attr) != AT_NORMAL) 27960786Sps { 28060786Sps /* 28160786Sps * Writing the last character on the last line 28260786Sps * of the display may have scrolled the screen. 28360786Sps * If we were in standout mode, clear_bg terminals 28460786Sps * will fill the new line with the standout color. 28560786Sps * Now we're in normal mode again, so clear the line. 28660786Sps */ 28760786Sps clear_eol(); 28860786Sps } 289170259Sdelphij#endif 290170259Sdelphij forw_prompt = 1; 29160786Sps } 29260786Sps 293330571Sdelphij if (nlines == 0 && !ignore_eoi && same_pos_bell) 29460786Sps eof_bell(); 29560786Sps else if (do_repaint) 29660786Sps repaint(); 29760786Sps first_time = 0; 29860786Sps (void) currline(BOTTOM); 29960786Sps} 30060786Sps 30160786Sps/* 30260786Sps * Display n lines, scrolling backward. 30360786Sps */ 30460786Sps public void 30560786Spsback(n, pos, force, only_last) 306330571Sdelphij int n; 30760786Sps POSITION pos; 30860786Sps int force; 30960786Sps int only_last; 31060786Sps{ 31160786Sps int nlines = 0; 31260786Sps int do_repaint; 31360786Sps 31460786Sps squish_check(); 31560786Sps do_repaint = (n > get_back_scroll() || (only_last && n > sc_height-1)); 316294286Sdelphij#if HILITE_SEARCH 317294286Sdelphij if (hilite_search == OPT_ONPLUS || is_filtering() || status_col) { 318294286Sdelphij prep_hilite((pos < 3*size_linebuf) ? 0 : pos - 3*size_linebuf, pos, -1); 319294286Sdelphij } 320294286Sdelphij#endif 32160786Sps while (--n >= 0) 32260786Sps { 32360786Sps /* 32460786Sps * Get the previous line of input. 32560786Sps */ 326294286Sdelphij#if HILITE_SEARCH 327294286Sdelphij pos = prev_unfiltered(pos); 328294286Sdelphij#endif 329294286Sdelphij 33060786Sps pos = back_line(pos); 33160786Sps if (pos == NULL_POSITION) 33260786Sps { 33360786Sps /* 33460786Sps * Beginning of file: stop here unless "force" is true. 33560786Sps */ 33660786Sps if (!force) 33760786Sps break; 33860786Sps } 33960786Sps /* 34060786Sps * Add the position of the previous line to the position table. 34160786Sps * Display the line on the screen. 34260786Sps */ 34360786Sps add_back_pos(pos); 34460786Sps nlines++; 34560786Sps if (!do_repaint) 34660786Sps { 34760786Sps home(); 34860786Sps add_line(); 34960786Sps put_line(); 35060786Sps } 35160786Sps } 35260786Sps 353294286Sdelphij if (nlines == 0 && same_pos_bell) 35460786Sps eof_bell(); 35560786Sps else if (do_repaint) 35660786Sps repaint(); 357170259Sdelphij else if (!oldbot) 358170259Sdelphij lower_left(); 35960786Sps (void) currline(BOTTOM); 36060786Sps} 36160786Sps 36260786Sps/* 36360786Sps * Display n more lines, forward. 36460786Sps * Start just after the line currently displayed at the bottom of the screen. 36560786Sps */ 36660786Sps public void 36760786Spsforward(n, force, only_last) 36860786Sps int n; 36960786Sps int force; 37060786Sps int only_last; 37160786Sps{ 37260786Sps POSITION pos; 37360786Sps 374191930Sdelphij if (get_quit_at_eof() && eof_displayed() && !(ch_getflags() & CH_HELPFILE)) 37560786Sps { 37660786Sps /* 37760786Sps * If the -e flag is set and we're trying to go 37860786Sps * forward from end-of-file, go on to the next file. 37960786Sps */ 38060786Sps if (edit_next(1)) 38160786Sps quit(QUIT_OK); 38260786Sps return; 38360786Sps } 38460786Sps 38560786Sps pos = position(BOTTOM_PLUS_ONE); 38660786Sps if (pos == NULL_POSITION && (!force || empty_lines(2, sc_height-1))) 38760786Sps { 38860786Sps if (ignore_eoi) 38960786Sps { 39060786Sps /* 39160786Sps * ignore_eoi is to support A_F_FOREVER. 39260786Sps * Back up until there is a line at the bottom 39360786Sps * of the screen. 39460786Sps */ 39560786Sps if (empty_screen()) 39660786Sps pos = ch_zero(); 39760786Sps else 39860786Sps { 39960786Sps do 40060786Sps { 40160786Sps back(1, position(TOP), 1, 0); 40260786Sps pos = position(BOTTOM_PLUS_ONE); 40360786Sps } while (pos == NULL_POSITION); 40460786Sps } 40560786Sps } else 40660786Sps { 40760786Sps eof_bell(); 40860786Sps return; 40960786Sps } 41060786Sps } 41160786Sps forw(n, pos, force, only_last, 0); 41260786Sps} 41360786Sps 41460786Sps/* 41560786Sps * Display n more lines, backward. 41660786Sps * Start just before the line currently displayed at the top of the screen. 41760786Sps */ 41860786Sps public void 41960786Spsbackward(n, force, only_last) 42060786Sps int n; 42160786Sps int force; 42260786Sps int only_last; 42360786Sps{ 42460786Sps POSITION pos; 42560786Sps 42660786Sps pos = position(TOP); 42760786Sps if (pos == NULL_POSITION && (!force || position(BOTTOM) == 0)) 42860786Sps { 42960786Sps eof_bell(); 43060786Sps return; 43160786Sps } 43260786Sps back(n, pos, force, only_last); 43360786Sps} 43460786Sps 43560786Sps/* 43660786Sps * Get the backwards scroll limit. 43760786Sps * Must call this function instead of just using the value of 43860786Sps * back_scroll, because the default case depends on sc_height and 43960786Sps * top_scroll, as well as back_scroll. 44060786Sps */ 44160786Sps public int 44260786Spsget_back_scroll() 44360786Sps{ 44460786Sps if (no_back_scroll) 44560786Sps return (0); 44660786Sps if (back_scroll >= 0) 44760786Sps return (back_scroll); 44860786Sps if (top_scroll) 44960786Sps return (sc_height - 2); 45060786Sps return (10000); /* infinity */ 45160786Sps} 452330571Sdelphij 453330571Sdelphij/* 454330571Sdelphij * Return number of displayable lines in the file. 455330571Sdelphij * Stop counting at screen height + 1. 456330571Sdelphij */ 457330571Sdelphij public int 458330571Sdelphijget_line_count() 459330571Sdelphij{ 460330571Sdelphij int nlines; 461330571Sdelphij POSITION pos = ch_zero(); 462330571Sdelphij 463330571Sdelphij for (nlines = 0; nlines <= sc_height; nlines++) 464330571Sdelphij { 465330571Sdelphij pos = forw_line(pos); 466330571Sdelphij if (pos == NULL_POSITION) break; 467330571Sdelphij } 468330571Sdelphij return nlines; 469330571Sdelphij} 470