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