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