]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/less/input.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / less / input.c
1 /*
2  * Copyright (C) 1984-2012  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, see the README file.
8  */
9
10
11 /*
12  * High level routines dealing with getting lines of input 
13  * from the file being viewed.
14  *
15  * When we speak of "lines" here, we mean PRINTABLE lines;
16  * lines processed with respect to the screen width.
17  * We use the term "raw line" to refer to lines simply
18  * delimited by newlines; not processed with respect to screen width.
19  */
20
21 #include "less.h"
22
23 extern int squeeze;
24 extern int chopline;
25 extern int hshift;
26 extern int quit_if_one_screen;
27 extern int sigs;
28 extern int ignore_eoi;
29 extern int status_col;
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 base_pos;
49         POSITION new_pos;
50         register int c;
51         int blankline;
52         int endline;
53         int backchars;
54
55 get_forw_line:
56         if (curr_pos == NULL_POSITION)
57         {
58                 null_line();
59                 return (NULL_POSITION);
60         }
61 #if HILITE_SEARCH
62         if (hilite_search == OPT_ONPLUS || is_filtering() || status_col)
63                 /*
64                  * If we are ignoring EOI (command F), only prepare
65                  * one line ahead, to avoid getting stuck waiting for
66                  * slow data without displaying the data we already have.
67                  * If we're not ignoring EOI, we *could* do the same, but
68                  * for efficiency we prepare several lines ahead at once.
69                  */
70                 prep_hilite(curr_pos, curr_pos + 3*size_linebuf, 
71                                 ignore_eoi ? 1 : -1);
72 #endif
73         if (ch_seek(curr_pos))
74         {
75                 null_line();
76                 return (NULL_POSITION);
77         }
78
79         /*
80          * Step back to the beginning of the line.
81          */
82         base_pos = curr_pos;
83         for (;;)
84         {
85                 if (ABORT_SIGS())
86                 {
87                         null_line();
88                         return (NULL_POSITION);
89                 }
90                 c = ch_back_get();
91                 if (c == EOI)
92                         break;
93                 if (c == '\n')
94                 {
95                         (void) ch_forw_get();
96                         break;
97                 }
98                 --base_pos;
99         }
100
101         /*
102          * Read forward again to the position we should start at.
103          */
104         prewind();
105         plinenum(base_pos);
106         (void) ch_seek(base_pos);
107         new_pos = base_pos;
108         while (new_pos < curr_pos)
109         {
110                 if (ABORT_SIGS())
111                 {
112                         null_line();
113                         return (NULL_POSITION);
114                 }
115                 c = ch_forw_get();
116                 backchars = pappend(c, new_pos);
117                 new_pos++;
118                 if (backchars > 0)
119                 {
120                         pshift_all();
121                         new_pos -= backchars;
122                         while (--backchars >= 0)
123                                 (void) ch_back_get();
124                 }
125         }
126         (void) pflushmbc();
127         pshift_all();
128
129         /*
130          * Read the first character to display.
131          */
132         c = ch_forw_get();
133         if (c == EOI)
134         {
135                 null_line();
136                 return (NULL_POSITION);
137         }
138         blankline = (c == '\n' || c == '\r');
139
140         /*
141          * Read each character in the line and append to the line buffer.
142          */
143         for (;;)
144         {
145                 if (ABORT_SIGS())
146                 {
147                         null_line();
148                         return (NULL_POSITION);
149                 }
150                 if (c == '\n' || c == EOI)
151                 {
152                         /*
153                          * End of the line.
154                          */
155                         backchars = pflushmbc();
156                         new_pos = ch_tell();
157                         if (backchars > 0 && !chopline && hshift == 0)
158                         {
159                                 new_pos -= backchars + 1;
160                                 endline = FALSE;
161                         } else
162                                 endline = TRUE;
163                         break;
164                 }
165                 if (c != '\r')
166                         blankline = 0;
167
168                 /*
169                  * Append the char to the line and get the next char.
170                  */
171                 backchars = pappend(c, ch_tell()-1);
172                 if (backchars > 0)
173                 {
174                         /*
175                          * The char won't fit in the line; the line
176                          * is too long to print in the screen width.
177                          * End the line here.
178                          */
179                         if (chopline || hshift > 0)
180                         {
181                                 do
182                                 {
183                                         if (ABORT_SIGS())
184                                         {
185                                                 null_line();
186                                                 return (NULL_POSITION);
187                                         }
188                                         c = ch_forw_get();
189                                 } while (c != '\n' && c != EOI);
190                                 new_pos = ch_tell();
191                                 endline = TRUE;
192                                 quit_if_one_screen = FALSE;
193                         } else
194                         {
195                                 new_pos = ch_tell() - backchars;
196                                 endline = FALSE;
197                         }
198                         break;
199                 }
200                 c = ch_forw_get();
201         }
202
203         pdone(endline, 1);
204
205 #if HILITE_SEARCH
206         if (is_filtered(base_pos))
207         {
208                 /*
209                  * We don't want to display this line.
210                  * Get the next line.
211                  */
212                 curr_pos = new_pos;
213                 goto get_forw_line;
214         }
215
216         if (status_col && is_hilited(base_pos, ch_tell()-1, 1, NULL))
217                 set_status_col('*');
218 #endif
219
220         if (squeeze && blankline)
221         {
222                 /*
223                  * This line is blank.
224                  * Skip down to the last contiguous blank line
225                  * and pretend it is the one which we are returning.
226                  */
227                 while ((c = ch_forw_get()) == '\n' || c == '\r')
228                         if (ABORT_SIGS())
229                         {
230                                 null_line();
231                                 return (NULL_POSITION);
232                         }
233                 if (c != EOI)
234                         (void) ch_back_get();
235                 new_pos = ch_tell();
236         }
237
238         return (new_pos);
239 }
240
241 /*
242  * Get the previous line.
243  * A "current" position is passed and a "new" position is returned.
244  * The current position is the position of the first character of
245  * a line.  The new position is the position of the first character
246  * of the PREVIOUS line.  The line obtained is the one starting at new_pos.
247  */
248         public POSITION
249 back_line(curr_pos)
250         POSITION curr_pos;
251 {
252         POSITION new_pos, begin_new_pos, base_pos;
253         int c;
254         int endline;
255         int backchars;
256
257 get_back_line:
258         if (curr_pos == NULL_POSITION || curr_pos <= ch_zero())
259         {
260                 null_line();
261                 return (NULL_POSITION);
262         }
263 #if HILITE_SEARCH
264         if (hilite_search == OPT_ONPLUS || is_filtering() || status_col)
265                 prep_hilite((curr_pos < 3*size_linebuf) ? 
266                                 0 : curr_pos - 3*size_linebuf, curr_pos, -1);
267 #endif
268         if (ch_seek(curr_pos-1))
269         {
270                 null_line();
271                 return (NULL_POSITION);
272         }
273
274         if (squeeze)
275         {
276                 /*
277                  * Find out if the "current" line was blank.
278                  */
279                 (void) ch_forw_get();    /* Skip the newline */
280                 c = ch_forw_get();       /* First char of "current" line */
281                 (void) ch_back_get();    /* Restore our position */
282                 (void) ch_back_get();
283
284                 if (c == '\n' || c == '\r')
285                 {
286                         /*
287                          * The "current" line was blank.
288                          * Skip over any preceding blank lines,
289                          * since we skipped them in forw_line().
290                          */
291                         while ((c = ch_back_get()) == '\n' || c == '\r')
292                                 if (ABORT_SIGS())
293                                 {
294                                         null_line();
295                                         return (NULL_POSITION);
296                                 }
297                         if (c == EOI)
298                         {
299                                 null_line();
300                                 return (NULL_POSITION);
301                         }
302                         (void) ch_forw_get();
303                 }
304         }
305
306         /*
307          * Scan backwards until we hit the beginning of the line.
308          */
309         for (;;)
310         {
311                 if (ABORT_SIGS())
312                 {
313                         null_line();
314                         return (NULL_POSITION);
315                 }
316                 c = ch_back_get();
317                 if (c == '\n')
318                 {
319                         /*
320                          * This is the newline ending the previous line.
321                          * We have hit the beginning of the line.
322                          */
323                         base_pos = ch_tell() + 1;
324                         break;
325                 }
326                 if (c == EOI)
327                 {
328                         /*
329                          * We have hit the beginning of the file.
330                          * This must be the first line in the file.
331                          * This must, of course, be the beginning of the line.
332                          */
333                         base_pos = ch_tell();
334                         break;
335                 }
336         }
337
338         /*
339          * Now scan forwards from the beginning of this line.
340          * We keep discarding "printable lines" (based on screen width)
341          * until we reach the curr_pos.
342          *
343          * {{ This algorithm is pretty inefficient if the lines
344          *    are much longer than the screen width, 
345          *    but I don't know of any better way. }}
346          */
347         new_pos = base_pos;
348         if (ch_seek(new_pos))
349         {
350                 null_line();
351                 return (NULL_POSITION);
352         }
353         endline = FALSE;
354         prewind();
355         plinenum(new_pos);
356     loop:
357         begin_new_pos = new_pos;
358         (void) ch_seek(new_pos);
359
360         do
361         {
362                 c = ch_forw_get();
363                 if (c == EOI || ABORT_SIGS())
364                 {
365                         null_line();
366                         return (NULL_POSITION);
367                 }
368                 new_pos++;
369                 if (c == '\n')
370                 {
371                         backchars = pflushmbc();
372                         if (backchars > 0 && !chopline && hshift == 0)
373                         {
374                                 backchars++;
375                                 goto shift;
376                         }
377                         endline = TRUE;
378                         break;
379                 }
380                 backchars = pappend(c, ch_tell()-1);
381                 if (backchars > 0)
382                 {
383                         /*
384                          * Got a full printable line, but we haven't
385                          * reached our curr_pos yet.  Discard the line
386                          * and start a new one.
387                          */
388                         if (chopline || hshift > 0)
389                         {
390                                 endline = TRUE;
391                                 quit_if_one_screen = FALSE;
392                                 break;
393                         }
394                 shift:
395                         pshift_all();
396                         while (backchars-- > 0)
397                         {
398                                 (void) ch_back_get();
399                                 new_pos--;
400                         }
401                         goto loop;
402                 }
403         } while (new_pos < curr_pos);
404
405         pdone(endline, 0);
406
407 #if HILITE_SEARCH
408         if (is_filtered(base_pos))
409         {
410                 /*
411                  * We don't want to display this line.
412                  * Get the previous line.
413                  */
414                 curr_pos = begin_new_pos;
415                 goto get_back_line;
416         }
417
418         if (status_col && curr_pos > 0 && is_hilited(base_pos, curr_pos-1, 1, NULL))
419                 set_status_col('*');
420 #endif
421
422         return (begin_new_pos);
423 }
424
425 /*
426  * Set attnpos.
427  */
428         public void
429 set_attnpos(pos)
430         POSITION pos;
431 {
432         int c;
433
434         if (pos != NULL_POSITION)
435         {
436                 if (ch_seek(pos))
437                         return;
438                 for (;;)
439                 {
440                         c = ch_forw_get();
441                         if (c == EOI)
442                                 return;
443                         if (c != '\n' && c != '\r')
444                                 break;
445                         pos++;
446                 }
447         }
448         start_attnpos = pos;
449         for (;;)
450         {
451                 c = ch_forw_get();
452                 pos++;
453                 if (c == EOI || c == '\n' || c == '\r')
454                         break;
455         }
456         end_attnpos = pos;
457 }