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