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