1/* $NetBSD: forwback.c,v 1.2 2011/07/03 19:51:26 tron Exp $ */ 2 3/* 4 * Copyright (C) 1984-2011 Mark Nudelman 5 * 6 * You may distribute under the terms of either the GNU General Public 7 * License or the Less License, as specified in the README file. 8 * 9 * For more information about less, or for information on how to 10 * contact the author, see the README file. 11 */ 12 13 14/* 15 * Primitives for displaying the file on the screen, 16 * scrolling either forward or backward. 17 */ 18 19#include "less.h" 20#include "position.h" 21 22public int screen_trashed; 23public int squished; 24public int no_back_scroll = 0; 25public int forw_prompt; 26 27extern int sigs; 28extern int top_scroll; 29extern int quiet; 30extern int sc_width, sc_height; 31extern int more_mode; 32extern int plusoption; 33extern int forw_scroll; 34extern int back_scroll; 35extern int ignore_eoi; 36extern int clear_bg; 37extern int final_attr; 38extern int oldbot; 39#if TAGS 40extern char *tagoption; 41#endif 42 43static void eof_bell __P((void)); 44static void eof_check __P((void)); 45 46/* 47 * Sound the bell to indicate user is trying to move past end of file. 48 */ 49 static void 50eof_bell() 51{ 52 if (quiet == NOT_QUIET) 53 bell(); 54 else 55 vbell(); 56} 57 58/* 59 * Check to see if the end of file is currently displayed. 60 */ 61 public int 62eof_displayed() 63{ 64 POSITION pos; 65 66 if (ignore_eoi) 67 return (0); 68 69 if (ch_length() == NULL_POSITION) 70 /* 71 * If the file length is not known, 72 * we can't possibly be displaying EOF. 73 */ 74 return (0); 75 76 /* 77 * If the bottom line is empty, we are at EOF. 78 * If the bottom line ends at the file length, 79 * we must be just at EOF. 80 */ 81 pos = position(BOTTOM_PLUS_ONE); 82 return (pos == NULL_POSITION || pos == ch_length()); 83} 84 85/* 86 * Check to see if the entire file is currently displayed. 87 */ 88 public int 89entire_file_displayed() 90{ 91 POSITION pos; 92 93 /* Make sure last line of file is displayed. */ 94 if (!eof_displayed()) 95 return (0); 96 97 /* Make sure first line of file is displayed. */ 98 pos = position(0); 99 return (pos == NULL_POSITION || pos == 0); 100} 101 102/* 103 * If the screen is "squished", repaint it. 104 * "Squished" means the first displayed line is not at the top 105 * of the screen; this can happen when we display a short file 106 * for the first time. 107 */ 108 public void 109squish_check() 110{ 111 if (!squished) 112 return; 113 squished = 0; 114 repaint(); 115} 116 117/* 118 * Display n lines, scrolling forward, 119 * starting at position pos in the input file. 120 * "force" means display the n lines even if we hit end of file. 121 * "only_last" means display only the last screenful if n > screen size. 122 * "nblank" is the number of blank lines to draw before the first 123 * real line. If nblank > 0, the pos must be NULL_POSITION. 124 * The first real line after the blanks will start at ch_zero(). 125 */ 126 public void 127forw(n, pos, force, only_last, nblank) 128 register int n; 129 POSITION pos; 130 int force; 131 int only_last; 132 int nblank; 133{ 134 int eof = 0; 135 int nlines = 0; 136 int do_repaint; 137 static int first_time = 1; 138 139 squish_check(); 140 141 /* 142 * do_repaint tells us not to display anything till the end, 143 * then just repaint the entire screen. 144 * We repaint if we are supposed to display only the last 145 * screenful and the request is for more than a screenful. 146 * Also if the request exceeds the forward scroll limit 147 * (but not if the request is for exactly a screenful, since 148 * repainting itself involves scrolling forward a screenful). 149 */ 150 do_repaint = (only_last && n > sc_height-1) || 151 (forw_scroll >= 0 && n > forw_scroll && n != sc_height-1); 152 153 if (!do_repaint) 154 { 155 if (top_scroll && n >= sc_height - 1 && pos != ch_length()) 156 { 157 /* 158 * Start a new screen. 159 * {{ This is not really desirable if we happen 160 * to hit eof in the middle of this screen, 161 * but we don't yet know if that will happen. }} 162 */ 163 pos_clear(); 164 add_forw_pos(pos); 165 force = 1; 166 clear(); 167 home(); 168 } 169 170 if (pos != position(BOTTOM_PLUS_ONE) || empty_screen()) 171 { 172 /* 173 * This is not contiguous with what is 174 * currently displayed. Clear the screen image 175 * (position table) and start a new screen. 176 */ 177 pos_clear(); 178 add_forw_pos(pos); 179 force = 1; 180 if (top_scroll) 181 { 182 clear(); 183 home(); 184 } else if (!first_time) 185 { 186 putstr("...skipping...\n"); 187 } 188 } 189 } 190 191 while (--n >= 0) 192 { 193 /* 194 * Read the next line of input. 195 */ 196 if (nblank > 0) 197 { 198 /* 199 * Still drawing blanks; don't get a line 200 * from the file yet. 201 * If this is the last blank line, get ready to 202 * read a line starting at ch_zero() next time. 203 */ 204 if (--nblank == 0) 205 pos = ch_zero(); 206 } else 207 { 208 /* 209 * Get the next line from the file. 210 */ 211 pos = forw_line(pos); 212 if (pos == NULL_POSITION) 213 { 214 /* 215 * End of file: stop here unless the top line 216 * is still empty, or "force" is true. 217 * Even if force is true, stop when the last 218 * line in the file reaches the top of screen. 219 */ 220 eof = 1; 221 if (!force && position(TOP) != NULL_POSITION) 222 break; 223 if (!empty_lines(0, 0) && 224 !empty_lines(1, 1) && 225 empty_lines(2, sc_height-1)) 226 break; 227 } 228 } 229 /* 230 * Add the position of the next line to the position table. 231 * Display the current line on the screen. 232 */ 233 add_forw_pos(pos); 234 nlines++; 235 if (do_repaint) 236 continue; 237 /* 238 * If this is the first screen displayed and 239 * we hit an early EOF (i.e. before the requested 240 * number of lines), we "squish" the display down 241 * at the bottom of the screen. 242 * But don't do this if a + option or a -t option 243 * was given. These options can cause us to 244 * start the display after the beginning of the file, 245 * and it is not appropriate to squish in that case. 246 */ 247 if ((first_time || more_mode) && 248 pos == NULL_POSITION && !top_scroll && 249#if TAGS 250 tagoption == NULL && 251#endif 252 !plusoption) 253 { 254 squished = 1; 255 continue; 256 } 257 put_line(); 258#if 0 259 /* {{ 260 * Can't call clear_eol here. The cursor might be at end of line 261 * on an ignaw terminal, so clear_eol would clear the last char 262 * of the current line instead of all of the next line. 263 * If we really need to do this on clear_bg terminals, we need 264 * to find a better way. 265 * }} 266 */ 267 if (clear_bg && apply_at_specials(final_attr) != AT_NORMAL) 268 { 269 /* 270 * Writing the last character on the last line 271 * of the display may have scrolled the screen. 272 * If we were in standout mode, clear_bg terminals 273 * will fill the new line with the standout color. 274 * Now we're in normal mode again, so clear the line. 275 */ 276 clear_eol(); 277 } 278#endif 279 forw_prompt = 1; 280 } 281 282 if (nlines == 0) 283 eof_bell(); 284 else if (do_repaint) 285 repaint(); 286 first_time = 0; 287 (void) currline(BOTTOM); 288} 289 290/* 291 * Display n lines, scrolling backward. 292 */ 293 public void 294back(n, pos, force, only_last) 295 register int n; 296 POSITION pos; 297 int force; 298 int only_last; 299{ 300 int nlines = 0; 301 int do_repaint; 302 303 squish_check(); 304 do_repaint = (n > get_back_scroll() || (only_last && n > sc_height-1)); 305 while (--n >= 0) 306 { 307 /* 308 * Get the previous line of input. 309 */ 310 pos = back_line(pos); 311 if (pos == NULL_POSITION) 312 { 313 /* 314 * Beginning of file: stop here unless "force" is true. 315 */ 316 if (!force) 317 break; 318 } 319 /* 320 * Add the position of the previous line to the position table. 321 * Display the line on the screen. 322 */ 323 add_back_pos(pos); 324 nlines++; 325 if (!do_repaint) 326 { 327 home(); 328 add_line(); 329 put_line(); 330 } 331 } 332 333 if (nlines == 0) 334 eof_bell(); 335 else if (do_repaint) 336 repaint(); 337 else if (!oldbot) 338 lower_left(); 339 (void) currline(BOTTOM); 340} 341 342/* 343 * Display n more lines, forward. 344 * Start just after the line currently displayed at the bottom of the screen. 345 */ 346 public void 347forward(n, force, only_last) 348 int n; 349 int force; 350 int only_last; 351{ 352 POSITION pos; 353 354 if (get_quit_at_eof() && eof_displayed() && !(ch_getflags() & CH_HELPFILE)) 355 { 356 /* 357 * If the -e flag is set and we're trying to go 358 * forward from end-of-file, go on to the next file. 359 */ 360 if (edit_next(1)) 361 quit(QUIT_OK); 362 return; 363 } 364 365 pos = position(BOTTOM_PLUS_ONE); 366 if (pos == NULL_POSITION && (!force || empty_lines(2, sc_height-1))) 367 { 368 if (ignore_eoi) 369 { 370 /* 371 * ignore_eoi is to support A_F_FOREVER. 372 * Back up until there is a line at the bottom 373 * of the screen. 374 */ 375 if (empty_screen()) 376 pos = ch_zero(); 377 else 378 { 379 do 380 { 381 back(1, position(TOP), 1, 0); 382 pos = position(BOTTOM_PLUS_ONE); 383 } while (pos == NULL_POSITION); 384 } 385 } else 386 { 387 eof_bell(); 388 return; 389 } 390 } 391 forw(n, pos, force, only_last, 0); 392} 393 394/* 395 * Display n more lines, backward. 396 * Start just before the line currently displayed at the top of the screen. 397 */ 398 public void 399backward(n, force, only_last) 400 int n; 401 int force; 402 int only_last; 403{ 404 POSITION pos; 405 406 pos = position(TOP); 407 if (pos == NULL_POSITION && (!force || position(BOTTOM) == 0)) 408 { 409 eof_bell(); 410 return; 411 } 412 back(n, pos, force, only_last); 413} 414 415/* 416 * Get the backwards scroll limit. 417 * Must call this function instead of just using the value of 418 * back_scroll, because the default case depends on sc_height and 419 * top_scroll, as well as back_scroll. 420 */ 421 public int 422get_back_scroll() 423{ 424 if (no_back_scroll) 425 return (0); 426 if (back_scroll >= 0) 427 return (back_scroll); 428 if (top_scroll) 429 return (sc_height - 2); 430 return (10000); /* infinity */ 431} 432