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