Annotation of src/usr.bin/less/input.c, Revision 1.6
1.1 etheisen 1: /*
1.5 shadchin 2: * Copyright (C) 1984-2011 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.4 millert 7: * For more information about less, or for information on how to
8: * contact the author, see the README file.
1.1 etheisen 9: */
10:
11:
12: /*
13: * High level routines dealing with getting lines of input
14: * from the file being viewed.
15: *
16: * When we speak of "lines" here, we mean PRINTABLE lines;
17: * lines processed with respect to the screen width.
18: * We use the term "raw line" to refer to lines simply
19: * delimited by newlines; not processed with respect to screen width.
20: */
21:
22: #include "less.h"
23:
24: extern int squeeze;
25: extern int chopline;
1.4 millert 26: extern int hshift;
27: extern int quit_if_one_screen;
1.6 ! millert 28: extern volatile sig_atomic_t sigs;
1.4 millert 29: extern int ignore_eoi;
1.5 shadchin 30: extern int status_col;
1.4 millert 31: extern POSITION start_attnpos;
32: extern POSITION end_attnpos;
1.1 etheisen 33: #if HILITE_SEARCH
34: extern int hilite_search;
35: extern int size_linebuf;
36: #endif
37:
38: /*
39: * Get the next line.
40: * A "current" position is passed and a "new" position is returned.
41: * The current position is the position of the first character of
42: * a line. The new position is the position of the first character
43: * of the NEXT line. The line obtained is the line starting at curr_pos.
44: */
45: public POSITION
46: forw_line(curr_pos)
47: POSITION curr_pos;
48: {
1.5 shadchin 49: POSITION base_pos;
1.1 etheisen 50: POSITION new_pos;
1.4 millert 51: register int c;
1.1 etheisen 52: int blankline;
53: int endline;
1.5 shadchin 54: int backchars;
1.1 etheisen 55:
1.5 shadchin 56: get_forw_line:
1.1 etheisen 57: if (curr_pos == NULL_POSITION)
58: {
59: null_line();
60: return (NULL_POSITION);
61: }
62: #if HILITE_SEARCH
1.5 shadchin 63: if (hilite_search == OPT_ONPLUS || is_filtering() || status_col)
1.4 millert 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);
1.1 etheisen 73: #endif
74: if (ch_seek(curr_pos))
75: {
76: null_line();
77: return (NULL_POSITION);
78: }
79:
1.5 shadchin 80: /*
81: * Step back to the beginning of the line.
82: */
83: base_pos = curr_pos;
84: for (;;)
85: {
86: if (ABORT_SIGS())
87: {
88: null_line();
89: return (NULL_POSITION);
90: }
91: c = ch_back_get();
92: if (c == EOI)
93: break;
94: if (c == '\n')
95: {
96: (void) ch_forw_get();
97: break;
98: }
99: --base_pos;
100: }
101:
102: /*
103: * Read forward again to the position we should start at.
104: */
105: prewind();
106: plinenum(base_pos);
107: (void) ch_seek(base_pos);
108: new_pos = base_pos;
109: while (new_pos < curr_pos)
110: {
111: if (ABORT_SIGS())
112: {
113: null_line();
114: return (NULL_POSITION);
115: }
116: c = ch_forw_get();
117: backchars = pappend(c, new_pos);
118: new_pos++;
119: if (backchars > 0)
120: {
121: pshift_all();
122: new_pos -= backchars;
123: while (--backchars >= 0)
124: (void) ch_back_get();
125: }
126: }
127: (void) pflushmbc();
128: pshift_all();
1.1 etheisen 129:
1.5 shadchin 130: /*
131: * Read the first character to display.
132: */
1.1 etheisen 133: c = ch_forw_get();
134: if (c == EOI)
135: {
136: null_line();
137: return (NULL_POSITION);
138: }
139: blankline = (c == '\n' || c == '\r');
140:
1.5 shadchin 141: /*
142: * Read each character in the line and append to the line buffer.
143: */
1.1 etheisen 144: for (;;)
145: {
146: if (ABORT_SIGS())
147: {
148: null_line();
149: return (NULL_POSITION);
150: }
151: if (c == '\n' || c == EOI)
152: {
153: /*
154: * End of the line.
155: */
1.5 shadchin 156: backchars = pflushmbc();
1.1 etheisen 157: new_pos = ch_tell();
1.5 shadchin 158: if (backchars > 0 && !chopline && hshift == 0)
159: {
160: new_pos -= backchars + 1;
161: endline = FALSE;
162: } else
163: endline = TRUE;
1.1 etheisen 164: break;
165: }
1.5 shadchin 166: if (c != '\r')
167: blankline = 0;
1.1 etheisen 168:
169: /*
170: * Append the char to the line and get the next char.
171: */
1.5 shadchin 172: backchars = pappend(c, ch_tell()-1);
173: if (backchars > 0)
1.1 etheisen 174: {
175: /*
176: * The char won't fit in the line; the line
177: * is too long to print in the screen width.
178: * End the line here.
179: */
1.4 millert 180: if (chopline || hshift > 0)
1.1 etheisen 181: {
182: do
183: {
1.5 shadchin 184: if (ABORT_SIGS())
185: {
186: null_line();
187: return (NULL_POSITION);
188: }
1.1 etheisen 189: c = ch_forw_get();
190: } while (c != '\n' && c != EOI);
191: new_pos = ch_tell();
1.4 millert 192: endline = TRUE;
193: quit_if_one_screen = FALSE;
1.1 etheisen 194: } else
195: {
1.5 shadchin 196: new_pos = ch_tell() - backchars;
1.4 millert 197: endline = FALSE;
1.1 etheisen 198: }
199: break;
200: }
201: c = ch_forw_get();
202: }
1.5 shadchin 203:
204: pdone(endline, 1);
205:
206: #if HILITE_SEARCH
207: if (is_filtered(base_pos))
208: {
209: /*
210: * We don't want to display this line.
211: * Get the next line.
212: */
213: curr_pos = new_pos;
214: goto get_forw_line;
215: }
216:
217: if (status_col && is_hilited(base_pos, ch_tell()-1, 1, NULL))
218: set_status_col('*');
219: #endif
1.1 etheisen 220:
221: if (squeeze && blankline)
222: {
223: /*
224: * This line is blank.
225: * Skip down to the last contiguous blank line
226: * and pretend it is the one which we are returning.
227: */
228: while ((c = ch_forw_get()) == '\n' || c == '\r')
229: if (ABORT_SIGS())
230: {
231: null_line();
232: return (NULL_POSITION);
233: }
234: if (c != EOI)
235: (void) ch_back_get();
236: new_pos = ch_tell();
237: }
238:
239: return (new_pos);
240: }
241:
242: /*
243: * Get the previous line.
244: * A "current" position is passed and a "new" position is returned.
245: * The current position is the position of the first character of
246: * a line. The new position is the position of the first character
247: * of the PREVIOUS line. The line obtained is the one starting at new_pos.
248: */
249: public POSITION
250: back_line(curr_pos)
251: POSITION curr_pos;
252: {
1.5 shadchin 253: POSITION new_pos, begin_new_pos, base_pos;
1.1 etheisen 254: int c;
255: int endline;
1.5 shadchin 256: int backchars;
1.1 etheisen 257:
1.5 shadchin 258: get_back_line:
1.1 etheisen 259: if (curr_pos == NULL_POSITION || curr_pos <= ch_zero())
260: {
261: null_line();
262: return (NULL_POSITION);
263: }
264: #if HILITE_SEARCH
1.5 shadchin 265: if (hilite_search == OPT_ONPLUS || is_filtering() || status_col)
1.1 etheisen 266: prep_hilite((curr_pos < 3*size_linebuf) ?
1.4 millert 267: 0 : curr_pos - 3*size_linebuf, curr_pos, -1);
1.1 etheisen 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: */
1.5 shadchin 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 */
1.1 etheisen 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: */
1.5 shadchin 324: base_pos = ch_tell() + 1;
1.1 etheisen 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: */
1.5 shadchin 334: base_pos = ch_tell();
1.1 etheisen 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: */
1.5 shadchin 348: new_pos = base_pos;
1.1 etheisen 349: if (ch_seek(new_pos))
350: {
351: null_line();
352: return (NULL_POSITION);
353: }
1.4 millert 354: endline = FALSE;
1.5 shadchin 355: prewind();
356: plinenum(new_pos);
1.1 etheisen 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: {
1.5 shadchin 372: backchars = pflushmbc();
373: if (backchars > 0 && !chopline && hshift == 0)
374: {
375: backchars++;
376: goto shift;
377: }
1.4 millert 378: endline = TRUE;
1.1 etheisen 379: break;
380: }
1.5 shadchin 381: backchars = pappend(c, ch_tell()-1);
382: if (backchars > 0)
1.1 etheisen 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: */
1.4 millert 389: if (chopline || hshift > 0)
1.1 etheisen 390: {
1.4 millert 391: endline = TRUE;
392: quit_if_one_screen = FALSE;
1.1 etheisen 393: break;
394: }
1.5 shadchin 395: shift:
396: pshift_all();
397: while (backchars-- > 0)
398: {
399: (void) ch_back_get();
400: new_pos--;
401: }
1.1 etheisen 402: goto loop;
403: }
404: } while (new_pos < curr_pos);
405:
1.5 shadchin 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 && is_hilited(base_pos, ch_tell()-1, 1, NULL))
420: set_status_col('*');
421: #endif
1.1 etheisen 422:
423: return (begin_new_pos);
1.4 millert 424: }
425:
426: /*
427: * Set attnpos.
428: */
429: public void
430: set_attnpos(pos)
431: POSITION pos;
432: {
433: int c;
434:
435: if (pos != NULL_POSITION)
436: {
437: if (ch_seek(pos))
438: return;
439: for (;;)
440: {
441: c = ch_forw_get();
442: if (c == EOI)
443: return;
444: if (c != '\n' && c != '\r')
445: break;
446: pos++;
447: }
448: }
449: start_attnpos = pos;
450: for (;;)
451: {
452: c = ch_forw_get();
453: pos++;
454: if (c == EOI || c == '\n' || c == '\r')
455: break;
456: }
457: end_attnpos = pos;
1.1 etheisen 458: }