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