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