xref: /original-bsd/usr.bin/more/input.c (revision 2bb802fc)
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.2 (Berkeley) 07/25/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 "less.h"
35 
36 extern int squeeze;
37 extern int sigs;
38 extern char *line;
39 
40 /*
41  * Get the next line.
42  * A "current" position is passed and a "new" position is returned.
43  * The current position is the position of the first character of
44  * a line.  The new position is the position of the first character
45  * of the NEXT line.  The line obtained is the line starting at curr_pos.
46  */
47 	public POSITION
48 forw_line(curr_pos)
49 	POSITION curr_pos;
50 {
51 	POSITION new_pos;
52 	register int c;
53 
54 	if (curr_pos == NULL_POSITION || ch_seek(curr_pos))
55 		return (NULL_POSITION);
56 
57 	c = ch_forw_get();
58 	if (c == EOI)
59 		return (NULL_POSITION);
60 
61 	prewind();
62 	for (;;)
63 	{
64 		if (sigs)
65 			return (NULL_POSITION);
66 		if (c == '\n' || c == EOI)
67 		{
68 			/*
69 			 * End of the line.
70 			 */
71 			new_pos = ch_tell();
72 			break;
73 		}
74 
75 		/*
76 		 * Append the char to the line and get the next char.
77 		 */
78 		if (pappend(c))
79 		{
80 			/*
81 			 * The char won't fit in the line; the line
82 			 * is too long to print in the screen width.
83 			 * End the line here.
84 			 */
85 			new_pos = ch_tell() - 1;
86 			break;
87 		}
88 		c = ch_forw_get();
89 	}
90 	(void) pappend('\0');
91 
92 	if (squeeze && *line == '\0')
93 	{
94 		/*
95 		 * This line is blank.
96 		 * Skip down to the last contiguous blank line
97 		 * and pretend it is the one which we are returning.
98 		 */
99 		while ((c = ch_forw_get()) == '\n')
100 			if (sigs)
101 				return (NULL_POSITION);
102 		if (c != EOI)
103 			(void) ch_back_get();
104 		new_pos = ch_tell();
105 	}
106 
107 	return (new_pos);
108 }
109 
110 /*
111  * Get the previous line.
112  * A "current" position is passed and a "new" position is returned.
113  * The current position is the position of the first character of
114  * a line.  The new position is the position of the first character
115  * of the PREVIOUS line.  The line obtained is the one starting at new_pos.
116  */
117 	public POSITION
118 back_line(curr_pos)
119 	POSITION curr_pos;
120 {
121 	POSITION new_pos, begin_new_pos;
122 	int c;
123 
124 	if (curr_pos == NULL_POSITION || curr_pos <= (POSITION)0 ||
125 		ch_seek(curr_pos-1))
126 		return (NULL_POSITION);
127 
128 	if (squeeze)
129 	{
130 		/*
131 		 * Find out if the "current" line was blank.
132 		 */
133 		(void) ch_forw_get();	/* Skip the newline */
134 		c = ch_forw_get();	/* First char of "current" line */
135 		(void) ch_back_get();	/* Restore our position */
136 		(void) ch_back_get();
137 
138 		if (c == '\n')
139 		{
140 			/*
141 			 * The "current" line was blank.
142 			 * Skip over any preceeding blank lines,
143 			 * since we skipped them in forw_line().
144 			 */
145 			while ((c = ch_back_get()) == '\n')
146 				if (sigs)
147 					return (NULL_POSITION);
148 			if (c == EOI)
149 				return (NULL_POSITION);
150 			(void) ch_forw_get();
151 		}
152 	}
153 
154 	/*
155 	 * Scan backwards until we hit the beginning of the line.
156 	 */
157 	for (;;)
158 	{
159 		if (sigs)
160 			return (NULL_POSITION);
161 		c = ch_back_get();
162 		if (c == '\n')
163 		{
164 			/*
165 			 * This is the newline ending the previous line.
166 			 * We have hit the beginning of the line.
167 			 */
168 			new_pos = ch_tell() + 1;
169 			break;
170 		}
171 		if (c == EOI)
172 		{
173 			/*
174 			 * We have hit the beginning of the file.
175 			 * This must be the first line in the file.
176 			 * This must, of course, be the beginning of the line.
177 			 */
178 			new_pos = ch_tell();
179 			break;
180 		}
181 	}
182 
183 	/*
184 	 * Now scan forwards from the beginning of this line.
185 	 * We keep discarding "printable lines" (based on screen width)
186 	 * until we reach the curr_pos.
187 	 *
188 	 * {{ This algorithm is pretty inefficient if the lines
189 	 *    are much longer than the screen width,
190 	 *    but I don't know of any better way. }}
191 	 */
192 	if (ch_seek(new_pos))
193 		return (NULL_POSITION);
194     loop:
195 	begin_new_pos = new_pos;
196 	prewind();
197 
198 	do
199 	{
200 		c = ch_forw_get();
201 		if (c == EOI || sigs)
202 			return (NULL_POSITION);
203 		new_pos++;
204 		if (c == '\n')
205 			break;
206 		if (pappend(c))
207 		{
208 			/*
209 			 * Got a full printable line, but we haven't
210 			 * reached our curr_pos yet.  Discard the line
211 			 * and start a new one.
212 			 */
213 			(void) pappend('\0');
214 			(void) ch_back_get();
215 			new_pos--;
216 			goto loop;
217 		}
218 	} while (new_pos < curr_pos);
219 
220 	(void) pappend('\0');
221 
222 	return (begin_new_pos);
223 }
224