1a5f0fb15SPaul Saab /* 2*c77c4889SXin LI * Copyright (C) 1984-2024 Mark Nudelman 3a5f0fb15SPaul Saab * 4a5f0fb15SPaul Saab * You may distribute under the terms of either the GNU General Public 5a5f0fb15SPaul Saab * License or the Less License, as specified in the README file. 6a5f0fb15SPaul Saab * 796e55cc7SXin LI * For more information, see the README file. 8a5f0fb15SPaul Saab */ 9a5f0fb15SPaul Saab 10a5f0fb15SPaul Saab 11a5f0fb15SPaul Saab /* 12a5f0fb15SPaul Saab * Primitives for displaying the file on the screen, 13a5f0fb15SPaul Saab * scrolling either forward or backward. 14a5f0fb15SPaul Saab */ 15a5f0fb15SPaul Saab 16a5f0fb15SPaul Saab #include "less.h" 17a5f0fb15SPaul Saab #include "position.h" 18a5f0fb15SPaul Saab 1995270f73SXin LI extern int less_is_more; 2095270f73SXin LI 21*c77c4889SXin LI public lbool squished; 22a5f0fb15SPaul Saab public int no_back_scroll = 0; 23720c436cSXin LI public int forw_prompt; 2495270f73SXin LI public int first_time = 1; 25*c77c4889SXin LI public lbool no_eof_bell = FALSE; 26a5f0fb15SPaul Saab 27a5f0fb15SPaul Saab extern int sigs; 28a5f0fb15SPaul Saab extern int top_scroll; 29a5f0fb15SPaul Saab extern int quiet; 30a5f0fb15SPaul Saab extern int sc_width, sc_height; 3195270f73SXin LI extern int hshift; 3295270f73SXin LI extern int auto_wrap; 33*c77c4889SXin LI extern lbool plusoption; 34a5f0fb15SPaul Saab extern int forw_scroll; 35a5f0fb15SPaul Saab extern int back_scroll; 36a5f0fb15SPaul Saab extern int ignore_eoi; 3795270f73SXin LI extern int header_lines; 3895270f73SXin LI extern int header_cols; 39d713e089SXin LI extern int full_screen; 40*c77c4889SXin LI extern POSITION header_start_pos; 41a15691bfSXin LI #if HILITE_SEARCH 42*c77c4889SXin LI extern size_t size_linebuf; 43a15691bfSXin LI extern int hilite_search; 44a15691bfSXin LI extern int status_col; 45a15691bfSXin LI #endif 46a5f0fb15SPaul Saab #if TAGS 47a5f0fb15SPaul Saab extern char *tagoption; 48a5f0fb15SPaul Saab #endif 49a5f0fb15SPaul Saab 50a5f0fb15SPaul Saab /* 51a5f0fb15SPaul Saab * Sound the bell to indicate user is trying to move past end of file. 52a5f0fb15SPaul Saab */ 53d713e089SXin LI public void eof_bell(void) 54a5f0fb15SPaul Saab { 55*c77c4889SXin LI if (no_eof_bell) 56*c77c4889SXin LI return; 572235c7feSXin LI #if HAVE_TIME 582235c7feSXin LI static time_type last_eof_bell = 0; 592235c7feSXin LI time_type now = get_time(); 602235c7feSXin LI if (now == last_eof_bell) /* max once per second */ 612235c7feSXin LI return; 622235c7feSXin LI last_eof_bell = now; 632235c7feSXin LI #endif 64a5f0fb15SPaul Saab if (quiet == NOT_QUIET) 65a5f0fb15SPaul Saab bell(); 66a5f0fb15SPaul Saab else 67a5f0fb15SPaul Saab vbell(); 68a5f0fb15SPaul Saab } 69a5f0fb15SPaul Saab 70a5f0fb15SPaul Saab /* 717374caaaSXin LI * Check to see if the end of file is currently displayed. 72a5f0fb15SPaul Saab */ 73*c77c4889SXin LI public lbool eof_displayed(void) 74a5f0fb15SPaul Saab { 75a5f0fb15SPaul Saab POSITION pos; 76a5f0fb15SPaul Saab 77a5f0fb15SPaul Saab if (ignore_eoi) 78*c77c4889SXin LI return (FALSE); 797374caaaSXin LI 807374caaaSXin LI if (ch_length() == NULL_POSITION) 817374caaaSXin LI /* 827374caaaSXin LI * If the file length is not known, 837374caaaSXin LI * we can't possibly be displaying EOF. 847374caaaSXin LI */ 85*c77c4889SXin LI return (FALSE); 867374caaaSXin LI 87a5f0fb15SPaul Saab /* 88a5f0fb15SPaul Saab * If the bottom line is empty, we are at EOF. 89a5f0fb15SPaul Saab * If the bottom line ends at the file length, 90a5f0fb15SPaul Saab * we must be just at EOF. 91a5f0fb15SPaul Saab */ 92a5f0fb15SPaul Saab pos = position(BOTTOM_PLUS_ONE); 937374caaaSXin LI return (pos == NULL_POSITION || pos == ch_length()); 947374caaaSXin LI } 957374caaaSXin LI 967374caaaSXin LI /* 977374caaaSXin LI * Check to see if the entire file is currently displayed. 987374caaaSXin LI */ 99*c77c4889SXin LI public lbool entire_file_displayed(void) 1007374caaaSXin LI { 1017374caaaSXin LI POSITION pos; 1027374caaaSXin LI 1037374caaaSXin LI /* Make sure last line of file is displayed. */ 1047374caaaSXin LI if (!eof_displayed()) 105*c77c4889SXin LI return (FALSE); 1067374caaaSXin LI 1077374caaaSXin LI /* Make sure first line of file is displayed. */ 1087374caaaSXin LI pos = position(0); 1097374caaaSXin LI return (pos == NULL_POSITION || pos == 0); 110a5f0fb15SPaul Saab } 111a5f0fb15SPaul Saab 112a5f0fb15SPaul Saab /* 113a5f0fb15SPaul Saab * If the screen is "squished", repaint it. 114a5f0fb15SPaul Saab * "Squished" means the first displayed line is not at the top 115a5f0fb15SPaul Saab * of the screen; this can happen when we display a short file 116a5f0fb15SPaul Saab * for the first time. 117a5f0fb15SPaul Saab */ 118d713e089SXin LI public void squish_check(void) 119a5f0fb15SPaul Saab { 120a5f0fb15SPaul Saab if (!squished) 121a5f0fb15SPaul Saab return; 122*c77c4889SXin LI squished = FALSE; 123a5f0fb15SPaul Saab repaint(); 124a5f0fb15SPaul Saab } 125a5f0fb15SPaul Saab 126a5f0fb15SPaul Saab /* 12795270f73SXin LI * Read the first pfx columns of the next line. 12895270f73SXin LI * If skipeol==0 stop there, otherwise read and discard chars to end of line. 12995270f73SXin LI */ 130d713e089SXin LI static POSITION forw_line_pfx(POSITION pos, int pfx, int skipeol) 13195270f73SXin LI { 13295270f73SXin LI int save_sc_width = sc_width; 13395270f73SXin LI int save_auto_wrap = auto_wrap; 13495270f73SXin LI int save_hshift = hshift; 13595270f73SXin LI /* Set fake sc_width to force only pfx chars to be read. */ 13695270f73SXin LI sc_width = pfx + line_pfx_width(); 13795270f73SXin LI auto_wrap = 0; 13895270f73SXin LI hshift = 0; 13995270f73SXin LI pos = forw_line_seg(pos, skipeol, FALSE, FALSE); 14095270f73SXin LI sc_width = save_sc_width; 14195270f73SXin LI auto_wrap = save_auto_wrap; 14295270f73SXin LI hshift = save_hshift; 14395270f73SXin LI return pos; 14495270f73SXin LI } 14595270f73SXin LI 14695270f73SXin LI /* 14795270f73SXin LI * Set header text color. 148*c77c4889SXin LI * Underline last line of headers, but not at header_start_pos 14995270f73SXin LI * (where there is no gap between the last header line and the next line). 15095270f73SXin LI */ 151d713e089SXin LI static void set_attr_header(int ln) 15295270f73SXin LI { 15395270f73SXin LI set_attr_line(AT_COLOR_HEADER); 154*c77c4889SXin LI if (ln+1 == header_lines && position(0) != header_start_pos) 15595270f73SXin LI set_attr_line(AT_UNDERLINE); 15695270f73SXin LI } 15795270f73SXin LI 15895270f73SXin LI /* 15995270f73SXin LI * Display file headers, overlaying text already drawn 16095270f73SXin LI * at top and left of screen. 16195270f73SXin LI */ 162d713e089SXin LI public int overlay_header(void) 16395270f73SXin LI { 16495270f73SXin LI int ln; 165*c77c4889SXin LI lbool moved = FALSE; 16695270f73SXin LI 16795270f73SXin LI if (header_lines > 0) 16895270f73SXin LI { 16995270f73SXin LI /* Draw header_lines lines from start of file at top of screen. */ 170*c77c4889SXin LI POSITION pos = header_start_pos; 17195270f73SXin LI home(); 17295270f73SXin LI for (ln = 0; ln < header_lines; ++ln) 17395270f73SXin LI { 17495270f73SXin LI pos = forw_line(pos); 17595270f73SXin LI set_attr_header(ln); 17695270f73SXin LI clear_eol(); 17795270f73SXin LI put_line(); 17895270f73SXin LI } 17995270f73SXin LI moved = TRUE; 18095270f73SXin LI } 18195270f73SXin LI if (header_cols > 0) 18295270f73SXin LI { 18395270f73SXin LI /* Draw header_cols columns at left of each line. */ 184*c77c4889SXin LI POSITION pos = header_start_pos; 18595270f73SXin LI home(); 18695270f73SXin LI for (ln = 0; ln < sc_height-1; ++ln) 18795270f73SXin LI { 18895270f73SXin LI if (ln >= header_lines) /* switch from header lines to normal lines */ 18995270f73SXin LI pos = position(ln); 19095270f73SXin LI if (pos == NULL_POSITION) 19195270f73SXin LI putchr('\n'); 19295270f73SXin LI else 19395270f73SXin LI { 19495270f73SXin LI /* Need skipeol for all header lines except the last one. */ 19595270f73SXin LI pos = forw_line_pfx(pos, header_cols, ln+1 < header_lines); 19695270f73SXin LI set_attr_header(ln); 19795270f73SXin LI put_line(); 19895270f73SXin LI } 19995270f73SXin LI } 20095270f73SXin LI moved = TRUE; 20195270f73SXin LI } 20295270f73SXin LI if (moved) 20395270f73SXin LI lower_left(); 20495270f73SXin LI return moved; 20595270f73SXin LI } 20695270f73SXin LI 20795270f73SXin LI /* 208a5f0fb15SPaul Saab * Display n lines, scrolling forward, 209a5f0fb15SPaul Saab * starting at position pos in the input file. 210a5f0fb15SPaul Saab * "force" means display the n lines even if we hit end of file. 211a5f0fb15SPaul Saab * "only_last" means display only the last screenful if n > screen size. 212a5f0fb15SPaul Saab * "nblank" is the number of blank lines to draw before the first 213a5f0fb15SPaul Saab * real line. If nblank > 0, the pos must be NULL_POSITION. 214a5f0fb15SPaul Saab * The first real line after the blanks will start at ch_zero(). 215a5f0fb15SPaul Saab */ 216*c77c4889SXin LI public void forw(int n, POSITION pos, lbool force, lbool only_last, int nblank) 217a5f0fb15SPaul Saab { 218a5f0fb15SPaul Saab int nlines = 0; 219*c77c4889SXin LI lbool do_repaint; 220a5f0fb15SPaul Saab 221*c77c4889SXin LI if (pos != NULL_POSITION) 222*c77c4889SXin LI pos = after_header_pos(pos); 223a5f0fb15SPaul Saab squish_check(); 224a5f0fb15SPaul Saab 225a5f0fb15SPaul Saab /* 226a5f0fb15SPaul Saab * do_repaint tells us not to display anything till the end, 227a5f0fb15SPaul Saab * then just repaint the entire screen. 228a5f0fb15SPaul Saab * We repaint if we are supposed to display only the last 229a5f0fb15SPaul Saab * screenful and the request is for more than a screenful. 230a5f0fb15SPaul Saab * Also if the request exceeds the forward scroll limit 231a5f0fb15SPaul Saab * (but not if the request is for exactly a screenful, since 232a5f0fb15SPaul Saab * repainting itself involves scrolling forward a screenful). 233a5f0fb15SPaul Saab */ 234a5f0fb15SPaul Saab do_repaint = (only_last && n > sc_height-1) || 235a5f0fb15SPaul Saab (forw_scroll >= 0 && n > forw_scroll && n != sc_height-1); 236a5f0fb15SPaul Saab 237a15691bfSXin LI #if HILITE_SEARCH 238f80a33eaSXin LI if (pos != NULL_POSITION && (hilite_search == OPT_ONPLUS || is_filtering() || status_col)) { 239*c77c4889SXin LI prep_hilite(pos, pos + (POSITION) (4*size_linebuf), ignore_eoi ? 1 : -1); 240a15691bfSXin LI pos = next_unfiltered(pos); 241a15691bfSXin LI } 242a15691bfSXin LI #endif 243a15691bfSXin LI 244a5f0fb15SPaul Saab if (!do_repaint) 245a5f0fb15SPaul Saab { 246a5f0fb15SPaul Saab if (top_scroll && n >= sc_height - 1 && pos != ch_length()) 247a5f0fb15SPaul Saab { 248a5f0fb15SPaul Saab /* 249a5f0fb15SPaul Saab * Start a new screen. 250a5f0fb15SPaul Saab * {{ This is not really desirable if we happen 251a5f0fb15SPaul Saab * to hit eof in the middle of this screen, 252a5f0fb15SPaul Saab * but we don't yet know if that will happen. }} 253a5f0fb15SPaul Saab */ 254a5f0fb15SPaul Saab pos_clear(); 255a5f0fb15SPaul Saab add_forw_pos(pos); 256*c77c4889SXin LI force = TRUE; 257720c436cSXin LI if (less_is_more == 0) { 258a5f0fb15SPaul Saab clear(); 259a5f0fb15SPaul Saab home(); 260a8f92a7cSPaul Saab } 261a5f0fb15SPaul Saab } 262a5f0fb15SPaul Saab 263a5f0fb15SPaul Saab if (pos != position(BOTTOM_PLUS_ONE) || empty_screen()) 264a5f0fb15SPaul Saab { 265a5f0fb15SPaul Saab /* 266a5f0fb15SPaul Saab * This is not contiguous with what is 267a5f0fb15SPaul Saab * currently displayed. Clear the screen image 268a5f0fb15SPaul Saab * (position table) and start a new screen. 269a5f0fb15SPaul Saab */ 270a5f0fb15SPaul Saab pos_clear(); 271a5f0fb15SPaul Saab add_forw_pos(pos); 272*c77c4889SXin LI force = TRUE; 273a5f0fb15SPaul Saab if (top_scroll) 274a5f0fb15SPaul Saab { 275a5f0fb15SPaul Saab clear(); 276a5f0fb15SPaul Saab home(); 277d713e089SXin LI } else if (!first_time && !is_filtering() && full_screen) 278a5f0fb15SPaul Saab { 279a5f0fb15SPaul Saab putstr("...skipping...\n"); 280a5f0fb15SPaul Saab } 281a5f0fb15SPaul Saab } 282a5f0fb15SPaul Saab } 283a5f0fb15SPaul Saab 284a5f0fb15SPaul Saab while (--n >= 0) 285a5f0fb15SPaul Saab { 286a5f0fb15SPaul Saab /* 287a5f0fb15SPaul Saab * Read the next line of input. 288a5f0fb15SPaul Saab */ 289a5f0fb15SPaul Saab if (nblank > 0) 290a5f0fb15SPaul Saab { 291a5f0fb15SPaul Saab /* 292a5f0fb15SPaul Saab * Still drawing blanks; don't get a line 293a5f0fb15SPaul Saab * from the file yet. 294a5f0fb15SPaul Saab * If this is the last blank line, get ready to 295a5f0fb15SPaul Saab * read a line starting at ch_zero() next time. 296a5f0fb15SPaul Saab */ 297a5f0fb15SPaul Saab if (--nblank == 0) 298a5f0fb15SPaul Saab pos = ch_zero(); 299a5f0fb15SPaul Saab } else 300a5f0fb15SPaul Saab { 301a5f0fb15SPaul Saab /* 302a5f0fb15SPaul Saab * Get the next line from the file. 303a5f0fb15SPaul Saab */ 304a5f0fb15SPaul Saab pos = forw_line(pos); 305a15691bfSXin LI #if HILITE_SEARCH 306a15691bfSXin LI pos = next_unfiltered(pos); 307a15691bfSXin LI #endif 308a5f0fb15SPaul Saab if (pos == NULL_POSITION) 309a5f0fb15SPaul Saab { 310a5f0fb15SPaul Saab /* 311a5f0fb15SPaul Saab * End of file: stop here unless the top line 312a5f0fb15SPaul Saab * is still empty, or "force" is true. 313a5f0fb15SPaul Saab * Even if force is true, stop when the last 314a5f0fb15SPaul Saab * line in the file reaches the top of screen. 315a5f0fb15SPaul Saab */ 316a5f0fb15SPaul Saab if (!force && position(TOP) != NULL_POSITION) 317a5f0fb15SPaul Saab break; 318a5f0fb15SPaul Saab if (!empty_lines(0, 0) && 319a5f0fb15SPaul Saab !empty_lines(1, 1) && 320a5f0fb15SPaul Saab empty_lines(2, sc_height-1)) 321a5f0fb15SPaul Saab break; 322a5f0fb15SPaul Saab } 323a5f0fb15SPaul Saab } 324a5f0fb15SPaul Saab /* 325a5f0fb15SPaul Saab * Add the position of the next line to the position table. 326a5f0fb15SPaul Saab * Display the current line on the screen. 327a5f0fb15SPaul Saab */ 328a5f0fb15SPaul Saab add_forw_pos(pos); 329a5f0fb15SPaul Saab nlines++; 330a5f0fb15SPaul Saab if (do_repaint) 331a5f0fb15SPaul Saab continue; 332a5f0fb15SPaul Saab /* 333a5f0fb15SPaul Saab * If this is the first screen displayed and 334a5f0fb15SPaul Saab * we hit an early EOF (i.e. before the requested 335a5f0fb15SPaul Saab * number of lines), we "squish" the display down 336a5f0fb15SPaul Saab * at the bottom of the screen. 337a5f0fb15SPaul Saab * But don't do this if a + option or a -t option 338a5f0fb15SPaul Saab * was given. These options can cause us to 339a5f0fb15SPaul Saab * start the display after the beginning of the file, 340a5f0fb15SPaul Saab * and it is not appropriate to squish in that case. 341a5f0fb15SPaul Saab */ 342720c436cSXin LI if ((first_time || less_is_more) && 343ea1e4cecSPaul Saab pos == NULL_POSITION && !top_scroll && 344d713e089SXin LI header_lines == 0 && header_cols == 0 && 345a5f0fb15SPaul Saab #if TAGS 346a5f0fb15SPaul Saab tagoption == NULL && 347a5f0fb15SPaul Saab #endif 348a5f0fb15SPaul Saab !plusoption) 349a5f0fb15SPaul Saab { 350*c77c4889SXin LI squished = TRUE; 351a5f0fb15SPaul Saab continue; 352a5f0fb15SPaul Saab } 353a5f0fb15SPaul Saab put_line(); 354720c436cSXin LI #if 0 355720c436cSXin LI /* {{ 356720c436cSXin LI * Can't call clear_eol here. The cursor might be at end of line 357720c436cSXin LI * on an ignaw terminal, so clear_eol would clear the last char 358720c436cSXin LI * of the current line instead of all of the next line. 359720c436cSXin LI * If we really need to do this on clear_bg terminals, we need 360720c436cSXin LI * to find a better way. 361720c436cSXin LI * }} 362720c436cSXin LI */ 36389dd99dcSXin LI if (clear_bg && apply_at_specials(final_attr) != AT_NORMAL) 364a5f0fb15SPaul Saab { 365a5f0fb15SPaul Saab /* 366a5f0fb15SPaul Saab * Writing the last character on the last line 367a5f0fb15SPaul Saab * of the display may have scrolled the screen. 368a5f0fb15SPaul Saab * If we were in standout mode, clear_bg terminals 369a5f0fb15SPaul Saab * will fill the new line with the standout color. 370a5f0fb15SPaul Saab * Now we're in normal mode again, so clear the line. 371a5f0fb15SPaul Saab */ 372a5f0fb15SPaul Saab clear_eol(); 373a5f0fb15SPaul Saab } 374720c436cSXin LI #endif 375720c436cSXin LI forw_prompt = 1; 376a5f0fb15SPaul Saab } 3776f26c71dSXin LI if (nlines == 0 && !ignore_eoi) 378a5f0fb15SPaul Saab eof_bell(); 379a5f0fb15SPaul Saab else if (do_repaint) 380a5f0fb15SPaul Saab repaint(); 38195270f73SXin LI else 38295270f73SXin LI { 38395270f73SXin LI overlay_header(); 38495270f73SXin LI /* lower_left(); {{ considered harmful? }} */ 38595270f73SXin LI } 386a5f0fb15SPaul Saab first_time = 0; 387a5f0fb15SPaul Saab (void) currline(BOTTOM); 388a5f0fb15SPaul Saab } 389a5f0fb15SPaul Saab 390a5f0fb15SPaul Saab /* 391a5f0fb15SPaul Saab * Display n lines, scrolling backward. 392a5f0fb15SPaul Saab */ 393*c77c4889SXin LI public void back(int n, POSITION pos, lbool force, lbool only_last) 394a5f0fb15SPaul Saab { 395a5f0fb15SPaul Saab int nlines = 0; 396*c77c4889SXin LI lbool do_repaint; 397a5f0fb15SPaul Saab 398a5f0fb15SPaul Saab squish_check(); 39995270f73SXin LI do_repaint = (n > get_back_scroll() || (only_last && n > sc_height-1) || header_lines > 0); 400a15691bfSXin LI #if HILITE_SEARCH 401f80a33eaSXin LI if (pos != NULL_POSITION && (hilite_search == OPT_ONPLUS || is_filtering() || status_col)) { 402*c77c4889SXin LI prep_hilite((pos < (POSITION) (3*size_linebuf)) ? 0 : pos - (POSITION) (3*size_linebuf), pos, -1); 403a15691bfSXin LI } 404a15691bfSXin LI #endif 405a5f0fb15SPaul Saab while (--n >= 0) 406a5f0fb15SPaul Saab { 407a5f0fb15SPaul Saab /* 408a5f0fb15SPaul Saab * Get the previous line of input. 409a5f0fb15SPaul Saab */ 410a15691bfSXin LI #if HILITE_SEARCH 411a15691bfSXin LI pos = prev_unfiltered(pos); 412a15691bfSXin LI #endif 413a5f0fb15SPaul Saab pos = back_line(pos); 414a5f0fb15SPaul Saab if (pos == NULL_POSITION) 415a5f0fb15SPaul Saab { 416a5f0fb15SPaul Saab /* 417a5f0fb15SPaul Saab * Beginning of file: stop here unless "force" is true. 418a5f0fb15SPaul Saab */ 419a5f0fb15SPaul Saab if (!force) 420a5f0fb15SPaul Saab break; 421a5f0fb15SPaul Saab } 422*c77c4889SXin LI if (pos != after_header_pos(pos)) 423*c77c4889SXin LI { 424*c77c4889SXin LI /* 425*c77c4889SXin LI * Don't allow scrolling back to before the current header line. 426*c77c4889SXin LI */ 427*c77c4889SXin LI break; 428*c77c4889SXin LI } 429a5f0fb15SPaul Saab /* 430a5f0fb15SPaul Saab * Add the position of the previous line to the position table. 431a5f0fb15SPaul Saab * Display the line on the screen. 432a5f0fb15SPaul Saab */ 433a5f0fb15SPaul Saab add_back_pos(pos); 434a5f0fb15SPaul Saab nlines++; 435a5f0fb15SPaul Saab if (!do_repaint) 436a5f0fb15SPaul Saab { 437a5f0fb15SPaul Saab home(); 438a5f0fb15SPaul Saab add_line(); 439a5f0fb15SPaul Saab put_line(); 440a5f0fb15SPaul Saab } 441a5f0fb15SPaul Saab } 4426f26c71dSXin LI if (nlines == 0) 443a5f0fb15SPaul Saab eof_bell(); 444a5f0fb15SPaul Saab else if (do_repaint) 445a5f0fb15SPaul Saab repaint(); 44695270f73SXin LI else 44795270f73SXin LI { 44895270f73SXin LI overlay_header(); 449720c436cSXin LI lower_left(); 45095270f73SXin LI } 451a5f0fb15SPaul Saab (void) currline(BOTTOM); 452a5f0fb15SPaul Saab } 453a5f0fb15SPaul Saab 454a5f0fb15SPaul Saab /* 455a5f0fb15SPaul Saab * Display n more lines, forward. 456a5f0fb15SPaul Saab * Start just after the line currently displayed at the bottom of the screen. 457a5f0fb15SPaul Saab */ 458*c77c4889SXin LI public void forward(int n, lbool force, lbool only_last) 459a5f0fb15SPaul Saab { 460a5f0fb15SPaul Saab POSITION pos; 461a5f0fb15SPaul Saab 4627374caaaSXin LI if (get_quit_at_eof() && eof_displayed() && !(ch_getflags() & CH_HELPFILE)) 463a5f0fb15SPaul Saab { 464a5f0fb15SPaul Saab /* 465a5f0fb15SPaul Saab * If the -e flag is set and we're trying to go 466a5f0fb15SPaul Saab * forward from end-of-file, go on to the next file. 467a5f0fb15SPaul Saab */ 468a5f0fb15SPaul Saab if (edit_next(1)) 469a5f0fb15SPaul Saab quit(QUIT_OK); 470a5f0fb15SPaul Saab return; 471a5f0fb15SPaul Saab } 472a5f0fb15SPaul Saab 473a5f0fb15SPaul Saab pos = position(BOTTOM_PLUS_ONE); 474a5f0fb15SPaul Saab if (pos == NULL_POSITION && (!force || empty_lines(2, sc_height-1))) 475a5f0fb15SPaul Saab { 476a5f0fb15SPaul Saab if (ignore_eoi) 477a5f0fb15SPaul Saab { 478a5f0fb15SPaul Saab /* 479a5f0fb15SPaul Saab * ignore_eoi is to support A_F_FOREVER. 480a5f0fb15SPaul Saab * Back up until there is a line at the bottom 481a5f0fb15SPaul Saab * of the screen. 482a5f0fb15SPaul Saab */ 483a5f0fb15SPaul Saab if (empty_screen()) 484a5f0fb15SPaul Saab pos = ch_zero(); 485a5f0fb15SPaul Saab else 486a5f0fb15SPaul Saab { 487a5f0fb15SPaul Saab do 488a5f0fb15SPaul Saab { 489a5f0fb15SPaul Saab back(1, position(TOP), 1, 0); 490a5f0fb15SPaul Saab pos = position(BOTTOM_PLUS_ONE); 491f80a33eaSXin LI } while (pos == NULL_POSITION && !ABORT_SIGS()); 492a5f0fb15SPaul Saab } 493a5f0fb15SPaul Saab } else 494a5f0fb15SPaul Saab { 495a5f0fb15SPaul Saab eof_bell(); 496a5f0fb15SPaul Saab return; 497a5f0fb15SPaul Saab } 498a5f0fb15SPaul Saab } 499a5f0fb15SPaul Saab forw(n, pos, force, only_last, 0); 500a5f0fb15SPaul Saab } 501a5f0fb15SPaul Saab 502a5f0fb15SPaul Saab /* 503a5f0fb15SPaul Saab * Display n more lines, backward. 504a5f0fb15SPaul Saab * Start just before the line currently displayed at the top of the screen. 505a5f0fb15SPaul Saab */ 506*c77c4889SXin LI public void backward(int n, lbool force, lbool only_last) 507a5f0fb15SPaul Saab { 508a5f0fb15SPaul Saab POSITION pos; 509a5f0fb15SPaul Saab 510a5f0fb15SPaul Saab pos = position(TOP); 511a5f0fb15SPaul Saab if (pos == NULL_POSITION && (!force || position(BOTTOM) == 0)) 512a5f0fb15SPaul Saab { 513a5f0fb15SPaul Saab eof_bell(); 514a5f0fb15SPaul Saab return; 515a5f0fb15SPaul Saab } 516a5f0fb15SPaul Saab back(n, pos, force, only_last); 517a5f0fb15SPaul Saab } 518a5f0fb15SPaul Saab 519a5f0fb15SPaul Saab /* 520a5f0fb15SPaul Saab * Get the backwards scroll limit. 521a5f0fb15SPaul Saab * Must call this function instead of just using the value of 522a5f0fb15SPaul Saab * back_scroll, because the default case depends on sc_height and 523a5f0fb15SPaul Saab * top_scroll, as well as back_scroll. 524a5f0fb15SPaul Saab */ 525d713e089SXin LI public int get_back_scroll(void) 526a5f0fb15SPaul Saab { 527a5f0fb15SPaul Saab if (no_back_scroll) 528a5f0fb15SPaul Saab return (0); 529a5f0fb15SPaul Saab if (back_scroll >= 0) 530a5f0fb15SPaul Saab return (back_scroll); 531a5f0fb15SPaul Saab if (top_scroll) 532a5f0fb15SPaul Saab return (sc_height - 2); 533a5f0fb15SPaul Saab return (10000); /* infinity */ 534a5f0fb15SPaul Saab } 535f6b74a7dSXin LI 536f6b74a7dSXin LI /* 537b7780dbeSXin LI * Will the entire file fit on one screen? 538f6b74a7dSXin LI */ 539d713e089SXin LI public int get_one_screen(void) 540f6b74a7dSXin LI { 541f6b74a7dSXin LI int nlines; 542b2ea2440SXin LI POSITION pos = ch_zero(); 543f6b74a7dSXin LI 544b7780dbeSXin LI for (nlines = 0; nlines < sc_height; nlines++) 545f6b74a7dSXin LI { 546f6b74a7dSXin LI pos = forw_line(pos); 547f6b74a7dSXin LI if (pos == NULL_POSITION) break; 548f6b74a7dSXin LI } 549b7780dbeSXin LI return (nlines < sc_height); 550f6b74a7dSXin LI } 551