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