forwback.c revision 60786
1/* 2 * Copyright (C) 1984-2000 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; 24 25extern int sigs; 26extern int top_scroll; 27extern int quiet; 28extern int sc_width, sc_height; 29extern int quit_at_eof; 30extern int plusoption; 31extern int forw_scroll; 32extern int back_scroll; 33extern int ignore_eoi; 34extern int clear_bg; 35extern int final_attr; 36#if TAGS 37extern char *tagoption; 38#endif 39 40/* 41 * Sound the bell to indicate user is trying to move past end of file. 42 */ 43 static void 44eof_bell() 45{ 46 if (quiet == NOT_QUIET) 47 bell(); 48 else 49 vbell(); 50} 51 52/* 53 * Check to see if the end of file is currently "displayed". 54 */ 55 static void 56eof_check() 57{ 58 POSITION pos; 59 60 if (ignore_eoi) 61 return; 62 if (ABORT_SIGS()) 63 return; 64 /* 65 * If the bottom line is empty, we are at EOF. 66 * If the bottom line ends at the file length, 67 * we must be just at EOF. 68 */ 69 pos = position(BOTTOM_PLUS_ONE); 70 if (pos == NULL_POSITION || pos == ch_length()) 71 hit_eof++; 72} 73 74/* 75 * If the screen is "squished", repaint it. 76 * "Squished" means the first displayed line is not at the top 77 * of the screen; this can happen when we display a short file 78 * for the first time. 79 */ 80 static void 81squish_check() 82{ 83 if (!squished) 84 return; 85 squished = 0; 86 repaint(); 87} 88 89/* 90 * Display n lines, scrolling forward, 91 * starting at position pos in the input file. 92 * "force" means display the n lines even if we hit end of file. 93 * "only_last" means display only the last screenful if n > screen size. 94 * "nblank" is the number of blank lines to draw before the first 95 * real line. If nblank > 0, the pos must be NULL_POSITION. 96 * The first real line after the blanks will start at ch_zero(). 97 */ 98 public void 99forw(n, pos, force, only_last, nblank) 100 register int n; 101 POSITION pos; 102 int force; 103 int only_last; 104 int nblank; 105{ 106 int eof = 0; 107 int nlines = 0; 108 int do_repaint; 109 static int first_time = 1; 110 111 squish_check(); 112 113 /* 114 * do_repaint tells us not to display anything till the end, 115 * then just repaint the entire screen. 116 * We repaint if we are supposed to display only the last 117 * screenful and the request is for more than a screenful. 118 * Also if the request exceeds the forward scroll limit 119 * (but not if the request is for exactly a screenful, since 120 * repainting itself involves scrolling forward a screenful). 121 */ 122 do_repaint = (only_last && n > sc_height-1) || 123 (forw_scroll >= 0 && n > forw_scroll && n != sc_height-1); 124 125 if (!do_repaint) 126 { 127 /* 128 * Forget any current line shift we might have 129 * (from the last line of the previous screenful). 130 */ 131 extern int cshift; 132 cshift = 0; 133 134 if (top_scroll && n >= sc_height - 1 && pos != ch_length()) 135 { 136 /* 137 * Start a new screen. 138 * {{ This is not really desirable if we happen 139 * to hit eof in the middle of this screen, 140 * but we don't yet know if that will happen. }} 141 */ 142 pos_clear(); 143 add_forw_pos(pos); 144 force = 1; 145 if (top_scroll == OPT_ONPLUS || first_time) 146 clear(); 147 home(); 148 } else 149 { 150 clear_bot(); 151 } 152 153 if (pos != position(BOTTOM_PLUS_ONE) || empty_screen()) 154 { 155 /* 156 * This is not contiguous with what is 157 * currently displayed. Clear the screen image 158 * (position table) and start a new screen. 159 */ 160 pos_clear(); 161 add_forw_pos(pos); 162 force = 1; 163 if (top_scroll) 164 { 165 if (top_scroll == OPT_ONPLUS) 166 clear(); 167 home(); 168 } else if (!first_time) 169 { 170 putstr("...skipping...\n"); 171 } 172 } 173 } 174 175 while (--n >= 0) 176 { 177 /* 178 * Read the next line of input. 179 */ 180 if (nblank > 0) 181 { 182 /* 183 * Still drawing blanks; don't get a line 184 * from the file yet. 185 * If this is the last blank line, get ready to 186 * read a line starting at ch_zero() next time. 187 */ 188 if (--nblank == 0) 189 pos = ch_zero(); 190 } else 191 { 192 /* 193 * Get the next line from the file. 194 */ 195 pos = forw_line(pos); 196 if (pos == NULL_POSITION) 197 { 198 /* 199 * End of file: stop here unless the top line 200 * is still empty, or "force" is true. 201 * Even if force is true, stop when the last 202 * line in the file reaches the top of screen. 203 */ 204 eof = 1; 205 if (!force && position(TOP) != NULL_POSITION) 206 break; 207 if (!empty_lines(0, 0) && 208 !empty_lines(1, 1) && 209 empty_lines(2, sc_height-1)) 210 break; 211 } 212 } 213 /* 214 * Add the position of the next line to the position table. 215 * Display the current line on the screen. 216 */ 217 add_forw_pos(pos); 218 nlines++; 219 if (do_repaint) 220 continue; 221 /* 222 * If this is the first screen displayed and 223 * we hit an early EOF (i.e. before the requested 224 * number of lines), we "squish" the display down 225 * at the bottom of the screen. 226 * But don't do this if a + option or a -t option 227 * was given. These options can cause us to 228 * start the display after the beginning of the file, 229 * and it is not appropriate to squish in that case. 230 */ 231 if (first_time && pos == NULL_POSITION && !top_scroll && 232#if TAGS 233 tagoption == NULL && 234#endif 235 !plusoption) 236 { 237 squished = 1; 238 continue; 239 } 240 if (top_scroll == OPT_ON) 241 clear_eol(); 242 put_line(); 243 if (clear_bg && final_attr != AT_NORMAL) 244 { 245 /* 246 * Writing the last character on the last line 247 * of the display may have scrolled the screen. 248 * If we were in standout mode, clear_bg terminals 249 * will fill the new line with the standout color. 250 * Now we're in normal mode again, so clear the line. 251 */ 252 clear_eol(); 253 } 254 } 255 256 if (ignore_eoi) 257 hit_eof = 0; 258 else if (eof && !ABORT_SIGS()) 259 hit_eof++; 260 else 261 eof_check(); 262 if (nlines == 0) 263 eof_bell(); 264 else if (do_repaint) 265 repaint(); 266 first_time = 0; 267 (void) currline(BOTTOM); 268} 269 270/* 271 * Display n lines, scrolling backward. 272 */ 273 public void 274back(n, pos, force, only_last) 275 register int n; 276 POSITION pos; 277 int force; 278 int only_last; 279{ 280 int nlines = 0; 281 int do_repaint; 282 283 squish_check(); 284 do_repaint = (n > get_back_scroll() || (only_last && n > sc_height-1)); 285 hit_eof = 0; 286 while (--n >= 0) 287 { 288 /* 289 * Get the previous line of input. 290 */ 291 pos = back_line(pos); 292 if (pos == NULL_POSITION) 293 { 294 /* 295 * Beginning of file: stop here unless "force" is true. 296 */ 297 if (!force) 298 break; 299 } 300 /* 301 * Add the position of the previous line to the position table. 302 * Display the line on the screen. 303 */ 304 add_back_pos(pos); 305 nlines++; 306 if (!do_repaint) 307 { 308 home(); 309 add_line(); 310 put_line(); 311 } 312 } 313 314 eof_check(); 315 if (nlines == 0) 316 eof_bell(); 317 else if (do_repaint) 318 repaint(); 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 (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