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