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