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