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