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