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