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