forwback.c revision 161478
17332Sjkh/* $FreeBSD: head/contrib/less/forwback.c 161478 2006-08-20 15:50:51Z delphij $ */ 27332Sjkh/* 37332Sjkh * Copyright (C) 1984-2005 Mark Nudelman 47332Sjkh * 57332Sjkh * You may distribute under the terms of either the GNU General Public 67332Sjkh * License or the Less License, as specified in the README file. 77332Sjkh * 87332Sjkh * For more information about less, or for information on how to 97332Sjkh * contact the author, see the README file. 107332Sjkh */ 117332Sjkh 127332Sjkh 137332Sjkh/* 147332Sjkh * Primitives for displaying the file on the screen, 1513765Smpp * scrolling either forward or backward. 167332Sjkh */ 177332Sjkh 187332Sjkh#include "less.h" 197332Sjkh#include "position.h" 207332Sjkh 217332Sjkhpublic int hit_eof; /* Keeps track of how many times we hit end of file */ 227332Sjkhpublic int screen_trashed; 237332Sjkhpublic int squished; 247332Sjkhpublic int no_back_scroll = 0; 257332Sjkh 267332Sjkhextern int sigs; 277332Sjkhextern int top_scroll; 2850477Speterextern int quiet; 297332Sjkhextern int sc_width, sc_height; 307332Sjkhextern int quit_at_eof; 317332Sjkhextern int more_mode; 327332Sjkhextern int plusoption; 337332Sjkhextern int forw_scroll; 347332Sjkhextern int back_scroll; 357332Sjkhextern int ignore_eoi; 367332Sjkhextern int clear_bg; 377332Sjkhextern int final_attr; 387332Sjkh#if TAGS 397332Sjkhextern char *tagoption; 407332Sjkh#endif 417332Sjkh 427332Sjkh/* 437332Sjkh * Sound the bell to indicate user is trying to move past end of file. 447332Sjkh */ 457332Sjkh static void 467332Sjkheof_bell() 477332Sjkh{ 487332Sjkh if (quiet == NOT_QUIET) 497332Sjkh bell(); 507332Sjkh else 517332Sjkh vbell(); 527332Sjkh} 537332Sjkh 547332Sjkh/* 557332Sjkh * Check to see if the end of file is currently "displayed". 567332Sjkh */ 577332Sjkh static void 587332Sjkheof_check() 597332Sjkh{ 607332Sjkh POSITION pos; 617332Sjkh 627332Sjkh if (ignore_eoi) 637332Sjkh return; 647332Sjkh if (ABORT_SIGS()) 657332Sjkh return; 667332Sjkh /* 677332Sjkh * If the bottom line is empty, we are at EOF. 687332Sjkh * If the bottom line ends at the file length, 697332Sjkh * we must be just at EOF. 707332Sjkh */ 717332Sjkh pos = position(BOTTOM_PLUS_ONE); 727332Sjkh if (pos == NULL_POSITION || pos == ch_length()) 737332Sjkh hit_eof++; 747332Sjkh} 757332Sjkh 767332Sjkh/* 777332Sjkh * If the screen is "squished", repaint it. 787332Sjkh * "Squished" means the first displayed line is not at the top 797332Sjkh * of the screen; this can happen when we display a short file 807332Sjkh * for the first time. 817332Sjkh */ 827332Sjkh static void 837332Sjkhsquish_check() 847332Sjkh{ 857332Sjkh if (!squished) 867332Sjkh return; 877332Sjkh squished = 0; 887332Sjkh repaint(); 897332Sjkh} 907332Sjkh 91143063Sjoerg/* 927332Sjkh * Display n lines, scrolling forward, 937332Sjkh * starting at position pos in the input file. 947332Sjkh * "force" means display the n lines even if we hit end of file. 957332Sjkh * "only_last" means display only the last screenful if n > screen size. 967332Sjkh * "nblank" is the number of blank lines to draw before the first 977332Sjkh * real line. If nblank > 0, the pos must be NULL_POSITION. 987332Sjkh * The first real line after the blanks will start at ch_zero(). 997332Sjkh */ 1007332Sjkh public void 1017332Sjkhforw(n, pos, force, only_last, nblank) 102143063Sjoerg register int n; 1037332Sjkh POSITION pos; 1047332Sjkh int force; 1057332Sjkh int only_last; 1067332Sjkh int nblank; 1077332Sjkh{ 1087332Sjkh int eof = 0; 109143063Sjoerg int nlines = 0; 1107332Sjkh int do_repaint; 1117332Sjkh static int first_time = 1; 1127332Sjkh 1137332Sjkh squish_check(); 1147332Sjkh 1157332Sjkh /* 1167332Sjkh * do_repaint tells us not to display anything till the end, 1177332Sjkh * then just repaint the entire screen. 1187332Sjkh * We repaint if we are supposed to display only the last 1197332Sjkh * screenful and the request is for more than a screenful. 1207332Sjkh * Also if the request exceeds the forward scroll limit 1217332Sjkh * (but not if the request is for exactly a screenful, since 1227332Sjkh * repainting itself involves scrolling forward a screenful). 1237332Sjkh */ 1247332Sjkh do_repaint = (only_last && n > sc_height-1) || 1257332Sjkh (forw_scroll >= 0 && n > forw_scroll && n != sc_height-1); 1267332Sjkh 1277332Sjkh if (!do_repaint) 1287332Sjkh { 1297332Sjkh if (top_scroll && n >= sc_height - 1 && pos != ch_length()) 1307332Sjkh { 1317332Sjkh /* 1327332Sjkh * Start a new screen. 1337332Sjkh * {{ This is not really desirable if we happen 1347332Sjkh * to hit eof in the middle of this screen, 1357332Sjkh * but we don't yet know if that will happen. }} 1367332Sjkh */ 137143063Sjoerg pos_clear(); 1387332Sjkh add_forw_pos(pos); 1397332Sjkh force = 1; 140 if (more_mode == 0) 141 { 142 if (top_scroll == OPT_ONPLUS || (first_time && top_scroll != OPT_ON)) 143 clear(); 144 home(); 145 } 146 } else 147 { 148 clear_bot(); 149 } 150 151 if (pos != position(BOTTOM_PLUS_ONE) || empty_screen()) 152 { 153 /* 154 * This is not contiguous with what is 155 * currently displayed. Clear the screen image 156 * (position table) and start a new screen. 157 */ 158 pos_clear(); 159 add_forw_pos(pos); 160 force = 1; 161 if (top_scroll) 162 { 163 if (top_scroll == OPT_ONPLUS) 164 clear(); 165 home(); 166 } else if (!first_time) 167 { 168 putstr("...skipping...\n"); 169 } 170 } 171 } 172 173 while (--n >= 0) 174 { 175 /* 176 * Read the next line of input. 177 */ 178 if (nblank > 0) 179 { 180 /* 181 * Still drawing blanks; don't get a line 182 * from the file yet. 183 * If this is the last blank line, get ready to 184 * read a line starting at ch_zero() next time. 185 */ 186 if (--nblank == 0) 187 pos = ch_zero(); 188 } else 189 { 190 /* 191 * Get the next line from the file. 192 */ 193 pos = forw_line(pos); 194 if (pos == NULL_POSITION) 195 { 196 /* 197 * End of file: stop here unless the top line 198 * is still empty, or "force" is true. 199 * Even if force is true, stop when the last 200 * line in the file reaches the top of screen. 201 */ 202 eof = 1; 203 if (!force && position(TOP) != NULL_POSITION) 204 break; 205 if (!empty_lines(0, 0) && 206 !empty_lines(1, 1) && 207 empty_lines(2, sc_height-1)) 208 break; 209 } 210 } 211 /* 212 * Add the position of the next line to the position table. 213 * Display the current line on the screen. 214 */ 215 add_forw_pos(pos); 216 nlines++; 217 if (do_repaint) 218 continue; 219 /* 220 * If this is the first screen displayed and 221 * we hit an early EOF (i.e. before the requested 222 * number of lines), we "squish" the display down 223 * at the bottom of the screen. 224 * But don't do this if a + option or a -t option 225 * was given. These options can cause us to 226 * start the display after the beginning of the file, 227 * and it is not appropriate to squish in that case. 228 */ 229 if ((first_time || more_mode) && 230 pos == NULL_POSITION && !top_scroll && 231#if TAGS 232 tagoption == NULL && 233#endif 234 !plusoption) 235 { 236 squished = 1; 237 continue; 238 } 239 if (top_scroll == OPT_ON) 240 clear_eol(); 241 put_line(); 242 if (clear_bg && apply_at_specials(final_attr) != AT_NORMAL) 243 { 244 /* 245 * Writing the last character on the last line 246 * of the display may have scrolled the screen. 247 * If we were in standout mode, clear_bg terminals 248 * will fill the new line with the standout color. 249 * Now we're in normal mode again, so clear the line. 250 */ 251 clear_eol(); 252 } 253 } 254 255 if (ignore_eoi) 256 hit_eof = 0; 257 else if (eof && !ABORT_SIGS()) 258 hit_eof++; 259 else 260 eof_check(); 261 if (nlines == 0) 262 eof_bell(); 263 else if (do_repaint) 264 repaint(); 265 first_time = 0; 266 (void) currline(BOTTOM); 267} 268 269/* 270 * Display n lines, scrolling backward. 271 */ 272 public void 273back(n, pos, force, only_last) 274 register int n; 275 POSITION pos; 276 int force; 277 int only_last; 278{ 279 int nlines = 0; 280 int do_repaint; 281 282 squish_check(); 283 do_repaint = (n > get_back_scroll() || (only_last && n > sc_height-1)); 284 hit_eof = 0; 285 while (--n >= 0) 286 { 287 /* 288 * Get the previous line of input. 289 */ 290 pos = back_line(pos); 291 if (pos == NULL_POSITION) 292 { 293 /* 294 * Beginning of file: stop here unless "force" is true. 295 */ 296 if (!force) 297 break; 298 } 299 /* 300 * Add the position of the previous line to the position table. 301 * Display the line on the screen. 302 */ 303 add_back_pos(pos); 304 nlines++; 305 if (!do_repaint) 306 { 307 home(); 308 add_line(); 309 put_line(); 310 } 311 } 312 313 eof_check(); 314 if (nlines == 0) 315 eof_bell(); 316 else if (do_repaint) 317 repaint(); 318 (void) currline(BOTTOM); 319} 320 321/* 322 * Display n more lines, forward. 323 * Start just after the line currently displayed at the bottom of the screen. 324 */ 325 public void 326forward(n, force, only_last) 327 int n; 328 int force; 329 int only_last; 330{ 331 POSITION pos; 332 333 if (quit_at_eof && hit_eof && !(ch_getflags() & CH_HELPFILE)) 334 { 335 /* 336 * If the -e flag is set and we're trying to go 337 * forward from end-of-file, go on to the next file. 338 */ 339 if (edit_next(1)) 340 quit(QUIT_OK); 341 return; 342 } 343 344 pos = position(BOTTOM_PLUS_ONE); 345 if (pos == NULL_POSITION && (!force || empty_lines(2, sc_height-1))) 346 { 347 if (ignore_eoi) 348 { 349 /* 350 * ignore_eoi is to support A_F_FOREVER. 351 * Back up until there is a line at the bottom 352 * of the screen. 353 */ 354 if (empty_screen()) 355 pos = ch_zero(); 356 else 357 { 358 do 359 { 360 back(1, position(TOP), 1, 0); 361 pos = position(BOTTOM_PLUS_ONE); 362 } while (pos == NULL_POSITION); 363 } 364 } else 365 { 366 eof_bell(); 367 hit_eof++; 368 return; 369 } 370 } 371 forw(n, pos, force, only_last, 0); 372} 373 374/* 375 * Display n more lines, backward. 376 * Start just before the line currently displayed at the top of the screen. 377 */ 378 public void 379backward(n, force, only_last) 380 int n; 381 int force; 382 int only_last; 383{ 384 POSITION pos; 385 386 pos = position(TOP); 387 if (pos == NULL_POSITION && (!force || position(BOTTOM) == 0)) 388 { 389 eof_bell(); 390 return; 391 } 392 back(n, pos, force, only_last); 393} 394 395/* 396 * Get the backwards scroll limit. 397 * Must call this function instead of just using the value of 398 * back_scroll, because the default case depends on sc_height and 399 * top_scroll, as well as back_scroll. 400 */ 401 public int 402get_back_scroll() 403{ 404 if (no_back_scroll) 405 return (0); 406 if (back_scroll >= 0) 407 return (back_scroll); 408 if (top_scroll) 409 return (sc_height - 2); 410 return (10000); /* infinity */ 411} 412