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