input.c revision 1.3 1 /* $NetBSD: input.c,v 1.3 1998/02/04 11:08:51 christos Exp $ */
2
3 /*
4 * Copyright (c) 1988 Mark Nudleman
5 * Copyright (c) 1988, 1993
6 * The Regents of the University of California. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37 #include <sys/cdefs.h>
38 #ifndef lint
39 #if 0
40 static char sccsid[] = "@(#)input.c 8.1 (Berkeley) 6/6/93";
41 #else
42 __RCSID("$NetBSD: input.c,v 1.3 1998/02/04 11:08:51 christos Exp $");
43 #endif
44 #endif /* not lint */
45
46 /*
47 * High level routines dealing with getting lines of input
48 * from the file being viewed.
49 *
50 * When we speak of "lines" here, we mean PRINTABLE lines;
51 * lines processed with respect to the screen width.
52 * We use the term "raw line" to refer to lines simply
53 * delimited by newlines; not processed with respect to screen width.
54 */
55
56 #include <sys/types.h>
57
58 #include "less.h"
59 #include "extern.h"
60
61 /*
62 * Get the next line.
63 * A "current" position is passed and a "new" position is returned.
64 * The current position is the position of the first character of
65 * a line. The new position is the position of the first character
66 * of the NEXT line. The line obtained is the line starting at curr_pos.
67 */
68 off_t
69 forw_line(curr_pos)
70 off_t curr_pos;
71 {
72 off_t new_pos;
73 int c;
74
75 if (curr_pos == NULL_POSITION || ch_seek(curr_pos))
76 return (NULL_POSITION);
77
78 c = ch_forw_get();
79 if (c == EOI)
80 return (NULL_POSITION);
81
82 prewind();
83 for (;;)
84 {
85 if (sigs)
86 return (NULL_POSITION);
87 if (c == '\n' || c == EOI)
88 {
89 /*
90 * End of the line.
91 */
92 new_pos = ch_tell();
93 break;
94 }
95
96 /*
97 * Append the char to the line and get the next char.
98 */
99 if (pappend(c))
100 {
101 /*
102 * The char won't fit in the line; the line
103 * is too long to print in the screen width.
104 * End the line here.
105 */
106 new_pos = ch_tell() - 1;
107 break;
108 }
109 c = ch_forw_get();
110 }
111 (void) pappend('\0');
112
113 if (squeeze && *line == '\0')
114 {
115 /*
116 * This line is blank.
117 * Skip down to the last contiguous blank line
118 * and pretend it is the one which we are returning.
119 */
120 while ((c = ch_forw_get()) == '\n')
121 if (sigs)
122 return (NULL_POSITION);
123 if (c != EOI)
124 (void) ch_back_get();
125 new_pos = ch_tell();
126 }
127
128 return (new_pos);
129 }
130
131 /*
132 * Get the previous line.
133 * A "current" position is passed and a "new" position is returned.
134 * The current position is the position of the first character of
135 * a line. The new position is the position of the first character
136 * of the PREVIOUS line. The line obtained is the one starting at new_pos.
137 */
138 off_t
139 back_line(curr_pos)
140 off_t curr_pos;
141 {
142 off_t new_pos, begin_new_pos;
143 int c;
144
145 if (curr_pos == NULL_POSITION || curr_pos <= (off_t)0 ||
146 ch_seek(curr_pos-1))
147 return (NULL_POSITION);
148
149 if (squeeze)
150 {
151 /*
152 * Find out if the "current" line was blank.
153 */
154 (void) ch_forw_get(); /* Skip the newline */
155 c = ch_forw_get(); /* First char of "current" line */
156 (void) ch_back_get(); /* Restore our position */
157 (void) ch_back_get();
158
159 if (c == '\n')
160 {
161 /*
162 * The "current" line was blank.
163 * Skip over any preceeding blank lines,
164 * since we skipped them in forw_line().
165 */
166 while ((c = ch_back_get()) == '\n')
167 if (sigs)
168 return (NULL_POSITION);
169 if (c == EOI)
170 return (NULL_POSITION);
171 (void) ch_forw_get();
172 }
173 }
174
175 /*
176 * Scan backwards until we hit the beginning of the line.
177 */
178 for (;;)
179 {
180 if (sigs)
181 return (NULL_POSITION);
182 c = ch_back_get();
183 if (c == '\n')
184 {
185 /*
186 * This is the newline ending the previous line.
187 * We have hit the beginning of the line.
188 */
189 new_pos = ch_tell() + 1;
190 break;
191 }
192 if (c == EOI)
193 {
194 /*
195 * We have hit the beginning of the file.
196 * This must be the first line in the file.
197 * This must, of course, be the beginning of the line.
198 */
199 new_pos = ch_tell();
200 break;
201 }
202 }
203
204 /*
205 * Now scan forwards from the beginning of this line.
206 * We keep discarding "printable lines" (based on screen width)
207 * until we reach the curr_pos.
208 *
209 * {{ This algorithm is pretty inefficient if the lines
210 * are much longer than the screen width,
211 * but I don't know of any better way. }}
212 */
213 if (ch_seek(new_pos))
214 return (NULL_POSITION);
215 loop:
216 begin_new_pos = new_pos;
217 prewind();
218
219 do
220 {
221 c = ch_forw_get();
222 if (c == EOI || sigs)
223 return (NULL_POSITION);
224 new_pos++;
225 if (c == '\n')
226 break;
227 if (pappend(c))
228 {
229 /*
230 * Got a full printable line, but we haven't
231 * reached our curr_pos yet. Discard the line
232 * and start a new one.
233 */
234 (void) pappend('\0');
235 (void) ch_back_get();
236 new_pos--;
237 goto loop;
238 }
239 } while (new_pos < curr_pos);
240
241 (void) pappend('\0');
242
243 return (begin_new_pos);
244 }
245