Merge from vendor branch OPENSSL:
[dragonfly.git] / contrib / less-381 / input.c
1 /*
2  * Copyright (C) 1984-2002  Mark Nudelman
3  *
4  * You may distribute under the terms of either the GNU General Public
5  * License or the Less License, as specified in the README file.
6  *
7  * For more information about less, or for information on how to 
8  * contact the author, see the README file.
9  */
10
11
12 /*
13  * High level routines dealing with getting lines of input 
14  * from the file being viewed.
15  *
16  * When we speak of "lines" here, we mean PRINTABLE lines;
17  * lines processed with respect to the screen width.
18  * We use the term "raw line" to refer to lines simply
19  * delimited by newlines; not processed with respect to screen width.
20  */
21
22 #include "less.h"
23
24 extern int squeeze;
25 extern int chopline;
26 extern int hshift;
27 extern int quit_if_one_screen;
28 extern int sigs;
29 extern int ignore_eoi;
30 extern POSITION start_attnpos;
31 extern POSITION end_attnpos;
32 #if HILITE_SEARCH
33 extern int hilite_search;
34 extern int size_linebuf;
35 #endif
36
37 /*
38  * Get the next line.
39  * A "current" position is passed and a "new" position is returned.
40  * The current position is the position of the first character of
41  * a line.  The new position is the position of the first character
42  * of the NEXT line.  The line obtained is the line starting at curr_pos.
43  */
44         public POSITION
45 forw_line(curr_pos)
46         POSITION curr_pos;
47 {
48         POSITION new_pos;
49         register int c;
50         int blankline;
51         int endline;
52
53         if (curr_pos == NULL_POSITION)
54         {
55                 null_line();
56                 return (NULL_POSITION);
57         }
58 #if HILITE_SEARCH
59         if (hilite_search == OPT_ONPLUS)
60                 /*
61                  * If we are ignoring EOI (command F), only prepare
62                  * one line ahead, to avoid getting stuck waiting for
63                  * slow data without displaying the data we already have.
64                  * If we're not ignoring EOI, we *could* do the same, but
65                  * for efficiency we prepare several lines ahead at once.
66                  */
67                 prep_hilite(curr_pos, curr_pos + 3*size_linebuf, 
68                                 ignore_eoi ? 1 : -1);
69 #endif
70         if (ch_seek(curr_pos))
71         {
72                 null_line();
73                 return (NULL_POSITION);
74         }
75
76         prewind();
77         plinenum(curr_pos);
78         (void) ch_seek(curr_pos);
79
80         c = ch_forw_get();
81         if (c == EOI)
82         {
83                 null_line();
84                 return (NULL_POSITION);
85         }
86         blankline = (c == '\n' || c == '\r');
87
88         for (;;)
89         {
90                 if (ABORT_SIGS())
91                 {
92                         null_line();
93                         return (NULL_POSITION);
94                 }
95                 if (c == '\n' || c == EOI)
96                 {
97                         /*
98                          * End of the line.
99                          */
100                         new_pos = ch_tell();
101                         endline = TRUE;
102                         break;
103                 }
104
105                 /*
106                  * Append the char to the line and get the next char.
107                  */
108                 if (pappend(c, ch_tell()-1))
109                 {
110                         /*
111                          * The char won't fit in the line; the line
112                          * is too long to print in the screen width.
113                          * End the line here.
114                          */
115                         if (chopline || hshift > 0)
116                         {
117                                 do
118                                 {
119                                         c = ch_forw_get();
120                                 } while (c != '\n' && c != EOI);
121                                 new_pos = ch_tell();
122                                 endline = TRUE;
123                                 quit_if_one_screen = FALSE;
124                         } else
125                         {
126                                 new_pos = ch_tell() - 1;
127                                 endline = FALSE;
128                         }
129                         break;
130                 }
131                 c = ch_forw_get();
132         }
133         pdone(endline);
134
135         if (squeeze && blankline)
136         {
137                 /*
138                  * This line is blank.
139                  * Skip down to the last contiguous blank line
140                  * and pretend it is the one which we are returning.
141                  */
142                 while ((c = ch_forw_get()) == '\n' || c == '\r')
143                         if (ABORT_SIGS())
144                         {
145                                 null_line();
146                                 return (NULL_POSITION);
147                         }
148                 if (c != EOI)
149                         (void) ch_back_get();
150                 new_pos = ch_tell();
151         }
152
153         return (new_pos);
154 }
155
156 /*
157  * Get the previous line.
158  * A "current" position is passed and a "new" position is returned.
159  * The current position is the position of the first character of
160  * a line.  The new position is the position of the first character
161  * of the PREVIOUS line.  The line obtained is the one starting at new_pos.
162  */
163         public POSITION
164 back_line(curr_pos)
165         POSITION curr_pos;
166 {
167         POSITION new_pos, begin_new_pos;
168         int c;
169         int endline;
170
171         if (curr_pos == NULL_POSITION || curr_pos <= ch_zero())
172         {
173                 null_line();
174                 return (NULL_POSITION);
175         }
176 #if HILITE_SEARCH
177         if (hilite_search == OPT_ONPLUS)
178                 prep_hilite((curr_pos < 3*size_linebuf) ? 
179                                 0 : curr_pos - 3*size_linebuf, curr_pos, -1);
180 #endif
181         if (ch_seek(curr_pos-1))
182         {
183                 null_line();
184                 return (NULL_POSITION);
185         }
186
187         if (squeeze)
188         {
189                 /*
190                  * Find out if the "current" line was blank.
191                  */
192                 (void) ch_forw_get();   /* Skip the newline */
193                 c = ch_forw_get();      /* First char of "current" line */
194                 (void) ch_back_get();   /* Restore our position */
195                 (void) ch_back_get();
196
197                 if (c == '\n' || c == '\r')
198                 {
199                         /*
200                          * The "current" line was blank.
201                          * Skip over any preceding blank lines,
202                          * since we skipped them in forw_line().
203                          */
204                         while ((c = ch_back_get()) == '\n' || c == '\r')
205                                 if (ABORT_SIGS())
206                                 {
207                                         null_line();
208                                         return (NULL_POSITION);
209                                 }
210                         if (c == EOI)
211                         {
212                                 null_line();
213                                 return (NULL_POSITION);
214                         }
215                         (void) ch_forw_get();
216                 }
217         }
218
219         /*
220          * Scan backwards until we hit the beginning of the line.
221          */
222         for (;;)
223         {
224                 if (ABORT_SIGS())
225                 {
226                         null_line();
227                         return (NULL_POSITION);
228                 }
229                 c = ch_back_get();
230                 if (c == '\n')
231                 {
232                         /*
233                          * This is the newline ending the previous line.
234                          * We have hit the beginning of the line.
235                          */
236                         new_pos = ch_tell() + 1;
237                         break;
238                 }
239                 if (c == EOI)
240                 {
241                         /*
242                          * We have hit the beginning of the file.
243                          * This must be the first line in the file.
244                          * This must, of course, be the beginning of the line.
245                          */
246                         new_pos = ch_tell();
247                         break;
248                 }
249         }
250
251         /*
252          * Now scan forwards from the beginning of this line.
253          * We keep discarding "printable lines" (based on screen width)
254          * until we reach the curr_pos.
255          *
256          * {{ This algorithm is pretty inefficient if the lines
257          *    are much longer than the screen width, 
258          *    but I don't know of any better way. }}
259          */
260         if (ch_seek(new_pos))
261         {
262                 null_line();
263                 return (NULL_POSITION);
264         }
265         endline = FALSE;
266     loop:
267         begin_new_pos = new_pos;
268         prewind();
269         plinenum(new_pos);
270         (void) ch_seek(new_pos);
271
272         do
273         {
274                 c = ch_forw_get();
275                 if (c == EOI || ABORT_SIGS())
276                 {
277                         null_line();
278                         return (NULL_POSITION);
279                 }
280                 new_pos++;
281                 if (c == '\n')
282                 {
283                         endline = TRUE;
284                         break;
285                 }
286                 if (pappend(c, ch_tell()-1))
287                 {
288                         /*
289                          * Got a full printable line, but we haven't
290                          * reached our curr_pos yet.  Discard the line
291                          * and start a new one.
292                          */
293                         if (chopline || hshift > 0)
294                         {
295                                 endline = TRUE;
296                                 quit_if_one_screen = FALSE;
297                                 break;
298                         }
299                         pdone(0);
300                         (void) ch_back_get();
301                         new_pos--;
302                         goto loop;
303                 }
304         } while (new_pos < curr_pos);
305
306         pdone(endline);
307
308         return (begin_new_pos);
309 }
310
311 /*
312  * Set attnpos.
313  */
314         public void
315 set_attnpos(pos)
316         POSITION pos;
317 {
318         int c;
319
320         if (pos != NULL_POSITION)
321         {
322                 if (ch_seek(pos))
323                         return;
324                 for (;;)
325                 {
326                         c = ch_forw_get();
327                         if (c == EOI)
328                                 return;
329                         if (c != '\n' && c != '\r')
330                                 break;
331                         pos++;
332                 }
333         }
334         start_attnpos = pos;
335         for (;;)
336         {
337                 c = ch_forw_get();
338                 pos++;
339                 if (c == EOI || c == '\n' || c == '\r')
340                         break;
341         }
342         end_attnpos = pos;
343 }