distribution by Mark Nudleman
[unix-history] / usr / src / usr.bin / more / input.c
CommitLineData
bfe13c81
KB
1/*
2 * Copyright (c) 1988 Mark Nudleman
3 * Copyright (c) 1988 Regents of the University of California.
4 * All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Mark Nudleman.
8 *
9 * Redistribution and use in source and binary forms are permitted
10 * provided that the above copyright notice and this paragraph are
11 * duplicated in all such forms and that any documentation,
12 * advertising materials, and other materials related to such
13 * distribution and use acknowledge that the software was developed
14 * by the University of California, Berkeley. The name of the
15 * University may not be used to endorse or promote products derived
16 * from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
19 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20 */
21
22#ifndef lint
23static char sccsid[] = "@(#)input.c 5.1 (Berkeley) %G%";
24#endif /* not lint */
25
26/*
27 * High level routines dealing with getting lines of input
28 * from the file being viewed.
29 *
30 * When we speak of "lines" here, we mean PRINTABLE lines;
31 * lines processed with respect to the screen width.
32 * We use the term "raw line" to refer to lines simply
33 * delimited by newlines; not processed with respect to screen width.
34 */
35
36#include "less.h"
37
38extern int squeeze;
39extern int sigs;
40extern char *line;
41
42/*
43 * Get the next line.
44 * A "current" position is passed and a "new" position is returned.
45 * The current position is the position of the first character of
46 * a line. The new position is the position of the first character
47 * of the NEXT line. The line obtained is the line starting at curr_pos.
48 */
49 public POSITION
50forw_line(curr_pos)
51 POSITION curr_pos;
52{
53 POSITION new_pos;
54 register int c;
55
56 if (curr_pos == NULL_POSITION || ch_seek(curr_pos))
57 return (NULL_POSITION);
58
59 c = ch_forw_get();
60 if (c == EOI)
61 return (NULL_POSITION);
62
63 prewind();
64 for (;;)
65 {
66 if (sigs)
67 return (NULL_POSITION);
68 if (c == '\n' || c == EOI)
69 {
70 /*
71 * End of the line.
72 */
73 new_pos = ch_tell();
74 break;
75 }
76
77 /*
78 * Append the char to the line and get the next char.
79 */
80 if (pappend(c))
81 {
82 /*
83 * The char won't fit in the line; the line
84 * is too long to print in the screen width.
85 * End the line here.
86 */
87 new_pos = ch_tell() - 1;
88 break;
89 }
90 c = ch_forw_get();
91 }
92 (void) pappend('\0');
93
94 if (squeeze && *line == '\0')
95 {
96 /*
97 * This line is blank.
98 * Skip down to the last contiguous blank line
99 * and pretend it is the one which we are returning.
100 */
101 while ((c = ch_forw_get()) == '\n')
102 if (sigs)
103 return (NULL_POSITION);
104 if (c != EOI)
105 (void) ch_back_get();
106 new_pos = ch_tell();
107 }
108
109 return (new_pos);
110}
111
112/*
113 * Get the previous line.
114 * A "current" position is passed and a "new" position is returned.
115 * The current position is the position of the first character of
116 * a line. The new position is the position of the first character
117 * of the PREVIOUS line. The line obtained is the one starting at new_pos.
118 */
119 public POSITION
120back_line(curr_pos)
121 POSITION curr_pos;
122{
123 POSITION new_pos, begin_new_pos;
124 int c;
125
126 if (curr_pos == NULL_POSITION || curr_pos <= (POSITION)0 ||
127 ch_seek(curr_pos-1))
128 return (NULL_POSITION);
129
130 if (squeeze)
131 {
132 /*
133 * Find out if the "current" line was blank.
134 */
135 (void) ch_forw_get(); /* Skip the newline */
136 c = ch_forw_get(); /* First char of "current" line */
137 (void) ch_back_get(); /* Restore our position */
138 (void) ch_back_get();
139
140 if (c == '\n')
141 {
142 /*
143 * The "current" line was blank.
144 * Skip over any preceeding blank lines,
145 * since we skipped them in forw_line().
146 */
147 while ((c = ch_back_get()) == '\n')
148 if (sigs)
149 return (NULL_POSITION);
150 if (c == EOI)
151 return (NULL_POSITION);
152 (void) ch_forw_get();
153 }
154 }
155
156 /*
157 * Scan backwards until we hit the beginning of the line.
158 */
159 for (;;)
160 {
161 if (sigs)
162 return (NULL_POSITION);
163 c = ch_back_get();
164 if (c == '\n')
165 {
166 /*
167 * This is the newline ending the previous line.
168 * We have hit the beginning of the line.
169 */
170 new_pos = ch_tell() + 1;
171 break;
172 }
173 if (c == EOI)
174 {
175 /*
176 * We have hit the beginning of the file.
177 * This must be the first line in the file.
178 * This must, of course, be the beginning of the line.
179 */
180 new_pos = ch_tell();
181 break;
182 }
183 }
184
185 /*
186 * Now scan forwards from the beginning of this line.
187 * We keep discarding "printable lines" (based on screen width)
188 * until we reach the curr_pos.
189 *
190 * {{ This algorithm is pretty inefficient if the lines
191 * are much longer than the screen width,
192 * but I don't know of any better way. }}
193 */
194 if (ch_seek(new_pos))
195 return (NULL_POSITION);
196 loop:
197 begin_new_pos = new_pos;
198 prewind();
199
200 do
201 {
202 c = ch_forw_get();
203 if (c == EOI || sigs)
204 return (NULL_POSITION);
205 new_pos++;
206 if (c == '\n')
207 break;
208 if (pappend(c))
209 {
210 /*
211 * Got a full printable line, but we haven't
212 * reached our curr_pos yet. Discard the line
213 * and start a new one.
214 */
215 (void) pappend('\0');
216 (void) ch_back_get();
217 new_pos--;
218 goto loop;
219 }
220 } while (new_pos < curr_pos);
221
222 (void) pappend('\0');
223
224 return (begin_new_pos);
225}