Added all of the MH sources, including RCS files, in
[mmh] / docs / historical / mh-6.8.5 / miscellany / less-177 / input.c
1 /*
2  * High level routines dealing with getting lines of input 
3  * from the file being viewed.
4  *
5  * When we speak of "lines" here, we mean PRINTABLE lines;
6  * lines processed with respect to the screen width.
7  * We use the term "raw line" to refer to lines simply
8  * delimited by newlines; not processed with respect to screen width.
9  */
10
11 #include "less.h"
12
13 extern int squeeze;
14 extern int chopline;
15 extern int sigs;
16
17 /*
18  * Get the next line.
19  * A "current" position is passed and a "new" position is returned.
20  * The current position is the position of the first character of
21  * a line.  The new position is the position of the first character
22  * of the NEXT line.  The line obtained is the line starting at curr_pos.
23  */
24         public POSITION
25 forw_line(curr_pos)
26         POSITION curr_pos;
27 {
28         POSITION new_pos;
29         register int c;
30         int blankline;
31         int endline;
32
33         if (curr_pos == NULL_POSITION || ch_seek(curr_pos))
34         {
35                 null_line();
36                 return (NULL_POSITION);
37         }
38
39         prewind();
40         plinenum(curr_pos);
41         (void) ch_seek(curr_pos);
42
43         c = ch_forw_get();
44         if (c == EOI)
45         {
46                 null_line();
47                 return (NULL_POSITION);
48         }
49         blankline = (c == '\n' || c == '\r');
50
51         for (;;)
52         {
53                 if (sigs)
54                 {
55                         null_line();
56                         return (NULL_POSITION);
57                 }
58                 if (c == '\n' || c == EOI)
59                 {
60                         /*
61                          * End of the line.
62                          */
63                         new_pos = ch_tell();
64                         endline = 1;
65                         break;
66                 }
67
68                 /*
69                  * Append the char to the line and get the next char.
70                  */
71                 if (pappend(c))
72                 {
73                         /*
74                          * The char won't fit in the line; the line
75                          * is too long to print in the screen width.
76                          * End the line here.
77                          */
78                         if (chopline)
79                         {
80                                 do
81                                 {
82                                         c = ch_forw_get();
83                                 } while (c != '\n' && c != EOI);
84                                 new_pos = ch_tell();
85                                 endline = 1;
86                         } else
87                         {
88                                 new_pos = ch_tell() - 1;
89                                 endline = 0;
90                         }
91                         break;
92                 }
93                 c = ch_forw_get();
94         }
95         pdone(endline);
96
97         if (squeeze && blankline)
98         {
99                 /*
100                  * This line is blank.
101                  * Skip down to the last contiguous blank line
102                  * and pretend it is the one which we are returning.
103                  */
104                 while ((c = ch_forw_get()) == '\n' || c == '\r')
105                         if (sigs)
106                         {
107                                 null_line();
108                                 return (NULL_POSITION);
109                         }
110                 if (c != EOI)
111                         (void) ch_back_get();
112                 new_pos = ch_tell();
113         }
114
115         return (new_pos);
116 }
117
118 /*
119  * Get the previous line.
120  * A "current" position is passed and a "new" position is returned.
121  * The current position is the position of the first character of
122  * a line.  The new position is the position of the first character
123  * of the PREVIOUS line.  The line obtained is the one starting at new_pos.
124  */
125         public POSITION
126 back_line(curr_pos)
127         POSITION curr_pos;
128 {
129         POSITION new_pos, begin_new_pos;
130         int c;
131         int endline;
132
133         if (curr_pos == NULL_POSITION || curr_pos <= ch_zero() ||
134                 ch_seek(curr_pos-1))
135         {
136                 null_line();
137                 return (NULL_POSITION);
138         }
139
140         if (squeeze)
141         {
142                 /*
143                  * Find out if the "current" line was blank.
144                  */
145                 (void) ch_forw_get();   /* Skip the newline */
146                 c = ch_forw_get();      /* First char of "current" line */
147                 (void) ch_back_get();   /* Restore our position */
148                 (void) ch_back_get();
149
150                 if (c == '\n')
151                 {
152                         /*
153                          * The "current" line was blank.
154                          * Skip over any preceding blank lines,
155                          * since we skipped them in forw_line().
156                          */
157                         while ((c = ch_back_get()) == '\n' || c == '\r')
158                                 if (sigs)
159                                 {
160                                         null_line();
161                                         return (NULL_POSITION);
162                                 }
163                         if (c == EOI)
164                         {
165                                 null_line();
166                                 return (NULL_POSITION);
167                         }
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                 {
179                         null_line();
180                         return (NULL_POSITION);
181                 }
182                 c = ch_back_get();
183                 if (c == '\n')
184                 {
185                         /*
186                          * This is the newline ending the previous line.
187                          * We have hit the beginning of the line.
188                          */
189                         new_pos = ch_tell() + 1;
190                         break;
191                 }
192                 if (c == EOI)
193                 {
194                         /*
195                          * We have hit the beginning of the file.
196                          * This must be the first line in the file.
197                          * This must, of course, be the beginning of the line.
198                          */
199                         new_pos = ch_tell();
200                         break;
201                 }
202         }
203
204         /*
205          * Now scan forwards from the beginning of this line.
206          * We keep discarding "printable lines" (based on screen width)
207          * until we reach the curr_pos.
208          *
209          * {{ This algorithm is pretty inefficient if the lines
210          *    are much longer than the screen width, 
211          *    but I don't know of any better way. }}
212          */
213         if (ch_seek(new_pos))
214         {
215                 null_line();
216                 return (NULL_POSITION);
217         }
218         endline = 0;
219     loop:
220         begin_new_pos = new_pos;
221         prewind();
222         plinenum(new_pos);
223         (void) ch_seek(new_pos);
224
225         do
226         {
227                 c = ch_forw_get();
228                 if (c == EOI || sigs)
229                 {
230                         null_line();
231                         return (NULL_POSITION);
232                 }
233                 new_pos++;
234                 if (c == '\n')
235                 {
236                         endline = 1;
237                         break;
238                 }
239                 if (pappend(c))
240                 {
241                         /*
242                          * Got a full printable line, but we haven't
243                          * reached our curr_pos yet.  Discard the line
244                          * and start a new one.
245                          */
246                         if (chopline)
247                         {
248                                 endline = 1;
249                                 break;
250                         }
251                         pdone(0);
252                         (void) ch_back_get();
253                         new_pos--;
254                         goto loop;
255                 }
256         } while (new_pos < curr_pos);
257
258         pdone(endline);
259
260         return (begin_new_pos);
261 }