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