1 /* $OpenBSD: forwback.c,v 1.4 2001/11/19 19:02:14 mpech Exp $ */ 2 3 /* 4 * Copyright (c) 1984,1985,1989,1994,1995 Mark Nudelman 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice in the documentation and/or other materials provided with 14 * the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY 17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 22 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 30 /* 31 * Primitives for displaying the file on the screen, 32 * scrolling either forward or backward. 33 */ 34 35 #include "less.h" 36 #include "position.h" 37 38 public int hit_eof; /* Keeps track of how many times we hit end of file */ 39 public int screen_trashed; 40 public int squished; 41 42 extern int sigs; 43 extern int top_scroll; 44 extern int quiet; 45 extern int sc_width, sc_height; 46 extern int quit_at_eof; 47 extern int less_mode; 48 extern int plusoption; 49 extern int forw_scroll; 50 extern int back_scroll; 51 extern int need_clr; 52 extern int ignore_eoi; 53 #if TAGS 54 extern char *tagoption; 55 #endif 56 57 /* 58 * Sound the bell to indicate user is trying to move past end of file. 59 */ 60 static void 61 eof_bell() 62 { 63 if (quiet == NOT_QUIET) 64 bell(); 65 else 66 vbell(); 67 } 68 69 /* 70 * Check to see if the end of file is currently "displayed". 71 */ 72 static void 73 eof_check() 74 { 75 POSITION pos; 76 77 if (ignore_eoi) 78 return; 79 if (ABORT_SIGS()) 80 return; 81 /* 82 * If the bottom line is empty, we are at EOF. 83 * If the bottom line ends at the file length, 84 * we must be just at EOF. 85 */ 86 pos = position(BOTTOM_PLUS_ONE); 87 if (pos == NULL_POSITION || pos == ch_length()) 88 hit_eof++; 89 } 90 91 /* 92 * If the screen is "squished", repaint it. 93 * "Squished" means the first displayed line is not at the top 94 * of the screen; this can happen when we display a short file 95 * for the first time. 96 */ 97 static void 98 squish_check() 99 { 100 if (!squished) 101 return; 102 squished = 0; 103 repaint(); 104 } 105 106 /* 107 * Display n lines, scrolling forward, 108 * starting at position pos in the input file. 109 * "force" means display the n lines even if we hit end of file. 110 * "only_last" means display only the last screenful if n > screen size. 111 * "nblank" is the number of blank lines to draw before the first 112 * real line. If nblank > 0, the pos must be NULL_POSITION. 113 * The first real line after the blanks will start at ch_zero(). 114 */ 115 public void 116 forw(n, pos, force, only_last, nblank) 117 int n; 118 POSITION pos; 119 int force; 120 int only_last; 121 int nblank; 122 { 123 int eof = 0; 124 int nlines = 0; 125 int do_repaint; 126 static int first_time = 1; 127 128 squish_check(); 129 130 /* 131 * do_repaint tells us not to display anything till the end, 132 * then just repaint the entire screen. 133 * We repaint if we are supposed to display only the last 134 * screenful and the request is for more than a screenful. 135 * Also if the request exceeds the forward scroll limit 136 * (but not if the request is for exactly a screenful, since 137 * repainting itself involves scrolling forward a screenful). 138 */ 139 do_repaint = (only_last && n > sc_height-1) || 140 (forw_scroll >= 0 && n > forw_scroll && n != sc_height-1); 141 142 if (!do_repaint) 143 { 144 if (top_scroll && n >= sc_height - 1 && pos != ch_length()) 145 { 146 /* 147 * Start a new screen. 148 * {{ This is not really desirable if we happen 149 * to hit eof in the middle of this screen, 150 * but we don't yet know if that will happen. }} 151 */ 152 if (top_scroll == OPT_ONPLUS || first_time) 153 clear(); 154 home(); 155 force = 1; 156 } else 157 { 158 clear_bot(); 159 } 160 161 if (pos != position(BOTTOM_PLUS_ONE) || empty_screen()) 162 { 163 /* 164 * This is not contiguous with what is 165 * currently displayed. Clear the screen image 166 * (position table) and start a new screen. 167 */ 168 pos_clear(); 169 add_forw_pos(pos); 170 force = 1; 171 if (top_scroll) 172 { 173 if (top_scroll == OPT_ONPLUS) 174 clear(); 175 home(); 176 } else if (!first_time) 177 { 178 putstr("...skipping...\n"); 179 } 180 } 181 } 182 183 while (--n >= 0) 184 { 185 /* 186 * Read the next line of input. 187 */ 188 if (nblank > 0) 189 { 190 /* 191 * Still drawing blanks; don't get a line 192 * from the file yet. 193 * If this is the last blank line, get ready to 194 * read a line starting at ch_zero() next time. 195 */ 196 if (--nblank == 0) 197 pos = ch_zero(); 198 } else 199 { 200 /* 201 * Get the next line from the file. 202 */ 203 pos = forw_line(pos); 204 if (pos == NULL_POSITION) 205 { 206 /* 207 * End of file: stop here unless the top line 208 * is still empty, or "force" is true. 209 */ 210 eof = 1; 211 if (!force && position(TOP) != NULL_POSITION) 212 break; 213 } 214 } 215 /* 216 * Add the position of the next line to the position table. 217 * Display the current line on the screen. 218 */ 219 add_forw_pos(pos); 220 nlines++; 221 if (do_repaint) 222 continue; 223 /* 224 * If this is the first screen displayed and 225 * we hit an early EOF (i.e. before the requested 226 * number of lines), we "squish" the display down 227 * at the bottom of the screen. 228 * But don't do this if a + option or a -t option 229 * was given. These options can cause us to 230 * start the display after the beginning of the file, 231 * and it is not appropriate to squish in that case. 232 */ 233 if (first_time && pos == NULL_POSITION && !top_scroll && 234 #if TAGS 235 tagoption == NULL && 236 #endif 237 !plusoption) 238 { 239 squished = 1; 240 continue; 241 } 242 if (top_scroll == 1) 243 clear_eol(); 244 put_line(); 245 } 246 247 if (ignore_eoi) 248 hit_eof = 0; 249 else if (eof && !ABORT_SIGS()) 250 hit_eof++; 251 else 252 eof_check(); 253 if (nlines == 0) 254 eof_bell(); 255 else if (do_repaint) 256 repaint(); 257 first_time = 0; 258 (void) currline(BOTTOM); 259 } 260 261 /* 262 * Display n lines, scrolling backward. 263 */ 264 public void 265 back(n, pos, force, only_last) 266 int n; 267 POSITION pos; 268 int force; 269 int only_last; 270 { 271 int nlines = 0; 272 int do_repaint; 273 274 squish_check(); 275 do_repaint = (n > get_back_scroll() || (only_last && n > sc_height-1)); 276 hit_eof = 0; 277 while (--n >= 0) 278 { 279 /* 280 * Get the previous line of input. 281 */ 282 pos = back_line(pos); 283 if (pos == NULL_POSITION) 284 { 285 /* 286 * Beginning of file: stop here unless "force" is true. 287 */ 288 if (!force) 289 break; 290 } 291 /* 292 * Add the position of the previous line to the position table. 293 * Display the line on the screen. 294 */ 295 add_back_pos(pos); 296 nlines++; 297 if (!do_repaint) 298 { 299 home(); 300 add_line(); 301 put_line(); 302 } 303 } 304 305 eof_check(); 306 if (nlines == 0) 307 eof_bell(); 308 else if (do_repaint) 309 repaint(); 310 (void) currline(BOTTOM); 311 } 312 313 /* 314 * Display n more lines, forward. 315 * Start just after the line currently displayed at the bottom of the screen. 316 */ 317 public void 318 forward(n, force, only_last) 319 int n; 320 int force; 321 int only_last; 322 { 323 POSITION pos; 324 325 if (quit_at_eof && hit_eof) 326 { 327 /* 328 * If the -e flag is set and we're trying to go 329 * forward from end-of-file, go on to the next file. 330 */ 331 if (edit_next(1)) 332 quit(QUIT_OK); 333 return; 334 } 335 336 pos = position(BOTTOM_PLUS_ONE); 337 if (pos == NULL_POSITION && (!force || empty_lines(2, sc_height-1))) 338 { 339 if (ignore_eoi) 340 { 341 /* 342 * ignore_eoi is to support A_F_FOREVER. 343 * Back up until there is a line at the bottom 344 * of the screen. 345 */ 346 if (empty_screen()) 347 pos = ch_zero(); 348 else 349 { 350 do 351 { 352 back(1, position(TOP), 1, 0); 353 pos = position(BOTTOM_PLUS_ONE); 354 } while (pos == NULL_POSITION); 355 } 356 } else { 357 eof_bell(); 358 hit_eof++; 359 return; 360 } 361 } 362 forw(n, pos, force, only_last, 0); 363 } 364 365 /* 366 * Display n more lines, backward. 367 * Start just before the line currently displayed at the top of the screen. 368 */ 369 public void 370 backward(n, force, only_last) 371 int n; 372 int force; 373 int only_last; 374 { 375 POSITION pos; 376 377 pos = position(TOP); 378 if (pos == NULL_POSITION && (!force || position(BOTTOM) == 0)) 379 { 380 eof_bell(); 381 return; 382 } 383 back(n, pos, force, only_last); 384 } 385 386 /* 387 * Get the backwards scroll limit. 388 * Must call this function instead of just using the value of 389 * back_scroll, because the default case depends on sc_height and 390 * top_scroll, as well as back_scroll. 391 */ 392 public int 393 get_back_scroll() 394 { 395 if (back_scroll >= 0) 396 return (back_scroll); 397 if (top_scroll) 398 return (sc_height - 2); 399 return (10000); /* infinity */ 400 } 401