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