Annotation of src/usr.bin/less/forwback.c, Revision 1.3
1.3 ! niklas 1: /* $OpenBSD$ */
! 2:
1.1 etheisen 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;
1.2 etheisen 47: extern int less_mode;
1.1 etheisen 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: register 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: register 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: }
1.2 etheisen 356: } else {
1.1 etheisen 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: }