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; 25public int display_next_file_or_exit = 0; 26 27extern int sigs; 28extern int top_scroll; 29extern int quiet; 30extern int sc_width, sc_height; 31extern int plusoption; 32extern int forw_scroll; 33extern int back_scroll; 34extern int ignore_eoi; 35extern int clear_bg; 36extern int final_attr; 37extern int oldbot; 38extern int unix2003_compat; 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 (!unix2003_compat) { 142 clear(); 143 home(); 144 } 145 } 146 147 if (pos != position(BOTTOM_PLUS_ONE) || empty_screen()) 148 { 149 /* 150 * This is not contiguous with what is 151 * currently displayed. Clear the screen image 152 * (position table) and start a new screen. 153 */ 154 pos_clear(); 155 add_forw_pos(pos); 156 force = 1; 157 if (top_scroll) 158 { 159 clear(); 160 home(); 161 } else if (!first_time) 162 { 163 putstr("...skipping...\n"); 164 } 165 } 166 } 167 168 while (--n >= 0) 169 { 170 /* 171 * Read the next line of input. 172 */ 173 if (nblank > 0) 174 { 175 /* 176 * Still drawing blanks; don't get a line 177 * from the file yet. 178 * If this is the last blank line, get ready to 179 * read a line starting at ch_zero() next time. 180 */ 181 if (--nblank == 0) 182 pos = ch_zero(); 183 } else 184 { 185 /* 186 * Get the next line from the file. 187 */ 188 pos = forw_line(pos); 189 if (pos == NULL_POSITION) 190 { 191 /* 192 * End of file: stop here unless the top line 193 * is still empty, or "force" is true. 194 * Even if force is true, stop when the last 195 * line in the file reaches the top of screen. 196 */ 197 eof = 1; 198 if (!force && position(TOP) != NULL_POSITION) 199 break; 200 if (!empty_lines(0, 0) && 201 !empty_lines(1, 1) && 202 empty_lines(2, sc_height-1)) 203 break; 204 } 205 } 206 /* 207 * Add the position of the next line to the position table. 208 * Display the current line on the screen. 209 */ 210 add_forw_pos(pos); 211 nlines++; 212 if (do_repaint) 213 continue; 214 /* 215 * If this is the first screen displayed and 216 * we hit an early EOF (i.e. before the requested 217 * number of lines), we "squish" the display down 218 * at the bottom of the screen. 219 * But don't do this if a + option or a -t option 220 * was given. These options can cause us to 221 * start the display after the beginning of the file, 222 * and it is not appropriate to squish in that case. 223 */ 224 if (first_time && pos == NULL_POSITION && !top_scroll && 225#if TAGS 226 tagoption == NULL && 227#endif 228 !plusoption) 229 { 230 squished = 1; 231 continue; 232 } 233 put_line(); 234#if 0 235 /* {{ 236 * Can't call clear_eol here. The cursor might be at end of line 237 * on an ignaw terminal, so clear_eol would clear the last char 238 * of the current line instead of all of the next line. 239 * If we really need to do this on clear_bg terminals, we need 240 * to find a better way. 241 * }} 242 */ 243 if (clear_bg && apply_at_specials(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#endif 255 forw_prompt = 1; 256 } 257 258 if (ignore_eoi) 259 hit_eof = 0; 260 else if (eof && !ABORT_SIGS()) 261 hit_eof++; 262 else 263 eof_check(); 264 if (nlines == 0) 265 eof_bell(); 266 else if (do_repaint) 267 repaint(); 268 first_time = 0; 269 (void) currline(BOTTOM); 270} 271 272/* 273 * Display n lines, scrolling backward. 274 */ 275 public void 276back(n, pos, force, only_last) 277 register int n; 278 POSITION pos; 279 int force; 280 int only_last; 281{ 282 int nlines = 0; 283 int do_repaint; 284 285 squish_check(); 286 do_repaint = (n > get_back_scroll() || (only_last && n > sc_height-1)); 287 hit_eof = 0; 288 while (--n >= 0) 289 { 290 /* 291 * Get the previous line of input. 292 */ 293 pos = back_line(pos); 294 if (pos == NULL_POSITION) 295 { 296 /* 297 * Beginning of file: stop here unless "force" is true. 298 */ 299 if (!force) 300 break; 301 } 302 /* 303 * Add the position of the previous line to the position table. 304 * Display the line on the screen. 305 */ 306 add_back_pos(pos); 307 nlines++; 308 if (!do_repaint) 309 { 310 home(); 311 add_line(); 312 put_line(); 313 } 314 } 315 316 eof_check(); 317 if (nlines == 0) 318 eof_bell(); 319 else if (do_repaint) 320 repaint(); 321 else if (!oldbot) 322 lower_left(); 323 (void) currline(BOTTOM); 324} 325 326/* 327 * Display n more lines, forward. 328 * Start just after the line currently displayed at the bottom of the screen. 329 */ 330 public void 331forward(n, force, only_last) 332 int n; 333 int force; 334 int only_last; 335{ 336 POSITION pos; 337 338 if (get_quit_at_eof() && hit_eof && !(ch_getflags() & CH_HELPFILE)) 339 { 340 /* 341 * If the -e flag is set and we're trying to go 342 * forward from end-of-file, go on to the next file. 343 */ 344 if (edit_next(1)) 345 quit(QUIT_OK); 346 return; 347 } 348 349 pos = position(BOTTOM_PLUS_ONE); 350 if (pos == NULL_POSITION && (!force || empty_lines(2, sc_height-1))) 351 { 352 if (ignore_eoi) 353 { 354 /* 355 * ignore_eoi is to support A_F_FOREVER. 356 * Back up until there is a line at the bottom 357 * of the screen. 358 */ 359 if (empty_screen()) 360 pos = ch_zero(); 361 else 362 { 363 do 364 { 365 back(1, position(TOP), 1, 0); 366 pos = position(BOTTOM_PLUS_ONE); 367 } while (pos == NULL_POSITION); 368 } 369 } else 370 { 371 eof_bell(); 372 hit_eof++; 373 return; 374 } 375 } 376 forw(n, pos, force, only_last, 0); 377} 378 379/* 380 * Display n more lines, backward. 381 * Start just before the line currently displayed at the top of the screen. 382 */ 383 public void 384backward(n, force, only_last) 385 int n; 386 int force; 387 int only_last; 388{ 389 POSITION pos; 390 391 pos = position(TOP); 392 if (pos == NULL_POSITION && (!force || position(BOTTOM) == 0)) 393 { 394 eof_bell(); 395 return; 396 } 397 back(n, pos, force, only_last); 398} 399 400/* 401 * Get the backwards scroll limit. 402 * Must call this function instead of just using the value of 403 * back_scroll, because the default case depends on sc_height and 404 * top_scroll, as well as back_scroll. 405 */ 406 public int 407get_back_scroll() 408{ 409 if (no_back_scroll) 410 return (0); 411 if (back_scroll >= 0) 412 return (back_scroll); 413 if (top_scroll) 414 return (sc_height - 2); 415 return (10000); /* infinity */ 416} 417