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