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