Annotation of src/usr.bin/less/input.c, Revision 1.7
1.1 etheisen 1: /*
1.7 ! shadchin 2: * Copyright (C) 1984-2012 Mark Nudelman
1.1 etheisen 3: *
1.4 millert 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.
1.1 etheisen 6: *
1.7 ! shadchin 7: * For more information, see the README file.
1.1 etheisen 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;
1.4 millert 25: extern int hshift;
26: extern int quit_if_one_screen;
1.6 millert 27: extern volatile sig_atomic_t sigs;
1.4 millert 28: extern int ignore_eoi;
1.5 shadchin 29: extern int status_col;
1.4 millert 30: extern POSITION start_attnpos;
31: extern POSITION end_attnpos;
1.1 etheisen 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: {
1.5 shadchin 48: POSITION base_pos;
1.1 etheisen 49: POSITION new_pos;
1.4 millert 50: register int c;
1.1 etheisen 51: int blankline;
52: int endline;
1.5 shadchin 53: int backchars;
1.1 etheisen 54:
1.5 shadchin 55: get_forw_line:
1.1 etheisen 56: if (curr_pos == NULL_POSITION)
57: {
58: null_line();
59: return (NULL_POSITION);
60: }
61: #if HILITE_SEARCH
1.5 shadchin 62: if (hilite_search == OPT_ONPLUS || is_filtering() || status_col)
1.4 millert 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);
1.1 etheisen 72: #endif
73: if (ch_seek(curr_pos))
74: {
75: null_line();
76: return (NULL_POSITION);
77: }
78:
1.5 shadchin 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();
1.1 etheisen 128:
1.5 shadchin 129: /*
130: * Read the first character to display.
131: */
1.1 etheisen 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:
1.5 shadchin 140: /*
141: * Read each character in the line and append to the line buffer.
142: */
1.1 etheisen 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: */
1.5 shadchin 155: backchars = pflushmbc();
1.1 etheisen 156: new_pos = ch_tell();
1.5 shadchin 157: if (backchars > 0 && !chopline && hshift == 0)
158: {
159: new_pos -= backchars + 1;
160: endline = FALSE;
161: } else
162: endline = TRUE;
1.1 etheisen 163: break;
164: }
1.5 shadchin 165: if (c != '\r')
166: blankline = 0;
1.1 etheisen 167:
168: /*
169: * Append the char to the line and get the next char.
170: */
1.5 shadchin 171: backchars = pappend(c, ch_tell()-1);
172: if (backchars > 0)
1.1 etheisen 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: */
1.4 millert 179: if (chopline || hshift > 0)
1.1 etheisen 180: {
181: do
182: {
1.5 shadchin 183: if (ABORT_SIGS())
184: {
185: null_line();
186: return (NULL_POSITION);
187: }
1.1 etheisen 188: c = ch_forw_get();
189: } while (c != '\n' && c != EOI);
190: new_pos = ch_tell();
1.4 millert 191: endline = TRUE;
192: quit_if_one_screen = FALSE;
1.1 etheisen 193: } else
194: {
1.5 shadchin 195: new_pos = ch_tell() - backchars;
1.4 millert 196: endline = FALSE;
1.1 etheisen 197: }
198: break;
199: }
200: c = ch_forw_get();
201: }
1.5 shadchin 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
1.1 etheisen 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: {
1.5 shadchin 252: POSITION new_pos, begin_new_pos, base_pos;
1.1 etheisen 253: int c;
254: int endline;
1.5 shadchin 255: int backchars;
1.1 etheisen 256:
1.5 shadchin 257: get_back_line:
1.1 etheisen 258: if (curr_pos == NULL_POSITION || curr_pos <= ch_zero())
259: {
260: null_line();
261: return (NULL_POSITION);
262: }
263: #if HILITE_SEARCH
1.5 shadchin 264: if (hilite_search == OPT_ONPLUS || is_filtering() || status_col)
1.1 etheisen 265: prep_hilite((curr_pos < 3*size_linebuf) ?
1.4 millert 266: 0 : curr_pos - 3*size_linebuf, curr_pos, -1);
1.1 etheisen 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: */
1.5 shadchin 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 */
1.1 etheisen 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: */
1.5 shadchin 323: base_pos = ch_tell() + 1;
1.1 etheisen 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: */
1.5 shadchin 333: base_pos = ch_tell();
1.1 etheisen 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: */
1.5 shadchin 347: new_pos = base_pos;
1.1 etheisen 348: if (ch_seek(new_pos))
349: {
350: null_line();
351: return (NULL_POSITION);
352: }
1.4 millert 353: endline = FALSE;
1.5 shadchin 354: prewind();
355: plinenum(new_pos);
1.1 etheisen 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: {
1.5 shadchin 371: backchars = pflushmbc();
372: if (backchars > 0 && !chopline && hshift == 0)
373: {
374: backchars++;
375: goto shift;
376: }
1.4 millert 377: endline = TRUE;
1.1 etheisen 378: break;
379: }
1.5 shadchin 380: backchars = pappend(c, ch_tell()-1);
381: if (backchars > 0)
1.1 etheisen 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: */
1.4 millert 388: if (chopline || hshift > 0)
1.1 etheisen 389: {
1.4 millert 390: endline = TRUE;
391: quit_if_one_screen = FALSE;
1.1 etheisen 392: break;
393: }
1.5 shadchin 394: shift:
395: pshift_all();
396: while (backchars-- > 0)
397: {
398: (void) ch_back_get();
399: new_pos--;
400: }
1.1 etheisen 401: goto loop;
402: }
403: } while (new_pos < curr_pos);
404:
1.5 shadchin 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:
1.7 ! shadchin 418: if (status_col && curr_pos > 0 && is_hilited(base_pos, curr_pos-1, 1, NULL))
1.5 shadchin 419: set_status_col('*');
420: #endif
1.1 etheisen 421:
422: return (begin_new_pos);
1.4 millert 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;
1.1 etheisen 457: }