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