Annotation of src/usr.bin/less/input.c, Revision 1.10
1.1 etheisen 1: /*
1.7 shadchin 2: * Copyright (C) 1984-2012 Mark Nudelman
1.10 ! nicm 3: * Modified for use with illumos by Garrett D'Amore.
! 4: * Copyright 2014 Garrett D'Amore <garrett@damore.org>
1.1 etheisen 5: *
1.4 millert 6: * You may distribute under the terms of either the GNU General Public
7: * License or the Less License, as specified in the README file.
1.1 etheisen 8: *
1.7 shadchin 9: * For more information, see the README file.
1.8 nicm 10: */
1.1 etheisen 11:
12: /*
1.8 nicm 13: * High level routines dealing with getting lines of input
1.1 etheisen 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.8 nicm 31: extern off_t start_attnpos;
32: extern off_t end_attnpos;
1.1 etheisen 33: extern int hilite_search;
34: extern int size_linebuf;
35:
36: /*
37: * Get the next line.
38: * A "current" position is passed and a "new" position is returned.
39: * The current position is the position of the first character of
40: * a line. The new position is the position of the first character
41: * of the NEXT line. The line obtained is the line starting at curr_pos.
42: */
1.8 nicm 43: off_t
44: forw_line(off_t curr_pos)
1.1 etheisen 45: {
1.8 nicm 46: off_t base_pos;
47: off_t new_pos;
1.9 tedu 48: int c;
1.1 etheisen 49: int blankline;
50: int endline;
1.5 shadchin 51: int backchars;
1.1 etheisen 52:
1.5 shadchin 53: get_forw_line:
1.8 nicm 54: if (curr_pos == -1) {
1.1 etheisen 55: null_line();
1.8 nicm 56: return (-1);
1.1 etheisen 57: }
1.5 shadchin 58: if (hilite_search == OPT_ONPLUS || is_filtering() || status_col)
1.4 millert 59: /*
60: * If we are ignoring EOI (command F), only prepare
61: * one line ahead, to avoid getting stuck waiting for
62: * slow data without displaying the data we already have.
63: * If we're not ignoring EOI, we *could* do the same, but
64: * for efficiency we prepare several lines ahead at once.
65: */
1.8 nicm 66: prep_hilite(curr_pos, curr_pos + 3*size_linebuf,
67: ignore_eoi ? 1 : -1);
68: if (ch_seek(curr_pos)) {
1.1 etheisen 69: null_line();
1.8 nicm 70: return (-1);
1.1 etheisen 71: }
72:
1.5 shadchin 73: /*
74: * Step back to the beginning of the line.
75: */
76: base_pos = curr_pos;
1.8 nicm 77: for (;;) {
78: if (ABORT_SIGS()) {
1.5 shadchin 79: null_line();
1.8 nicm 80: return (-1);
1.5 shadchin 81: }
82: c = ch_back_get();
83: if (c == EOI)
84: break;
1.8 nicm 85: if (c == '\n') {
1.5 shadchin 86: (void) ch_forw_get();
87: break;
88: }
89: --base_pos;
90: }
91:
92: /*
93: * Read forward again to the position we should start at.
94: */
1.8 nicm 95: prewind();
1.5 shadchin 96: plinenum(base_pos);
97: (void) ch_seek(base_pos);
98: new_pos = base_pos;
1.8 nicm 99: while (new_pos < curr_pos) {
100: if (ABORT_SIGS()) {
1.5 shadchin 101: null_line();
1.8 nicm 102: return (-1);
1.5 shadchin 103: }
104: c = ch_forw_get();
105: backchars = pappend(c, new_pos);
106: new_pos++;
1.8 nicm 107: if (backchars > 0) {
1.5 shadchin 108: pshift_all();
109: new_pos -= backchars;
110: while (--backchars >= 0)
111: (void) ch_back_get();
112: }
113: }
114: (void) pflushmbc();
115: pshift_all();
1.1 etheisen 116:
1.5 shadchin 117: /*
118: * Read the first character to display.
119: */
1.1 etheisen 120: c = ch_forw_get();
1.8 nicm 121: if (c == EOI) {
1.1 etheisen 122: null_line();
1.8 nicm 123: return (-1);
1.1 etheisen 124: }
125: blankline = (c == '\n' || c == '\r');
126:
1.5 shadchin 127: /*
128: * Read each character in the line and append to the line buffer.
129: */
1.8 nicm 130: for (;;) {
131: if (ABORT_SIGS()) {
1.1 etheisen 132: null_line();
1.8 nicm 133: return (-1);
1.1 etheisen 134: }
1.8 nicm 135: if (c == '\n' || c == EOI) {
1.1 etheisen 136: /*
137: * End of the line.
138: */
1.5 shadchin 139: backchars = pflushmbc();
1.1 etheisen 140: new_pos = ch_tell();
1.8 nicm 141: if (backchars > 0 && !chopline && hshift == 0) {
1.5 shadchin 142: new_pos -= backchars + 1;
143: endline = FALSE;
144: } else
145: endline = TRUE;
1.1 etheisen 146: break;
147: }
1.5 shadchin 148: if (c != '\r')
149: blankline = 0;
1.1 etheisen 150:
151: /*
152: * Append the char to the line and get the next char.
153: */
1.5 shadchin 154: backchars = pappend(c, ch_tell()-1);
1.8 nicm 155: if (backchars > 0) {
1.1 etheisen 156: /*
157: * The char won't fit in the line; the line
158: * is too long to print in the screen width.
159: * End the line here.
160: */
1.8 nicm 161: if (chopline || hshift > 0) {
162: do {
163: if (ABORT_SIGS()) {
1.5 shadchin 164: null_line();
1.8 nicm 165: return (-1);
1.5 shadchin 166: }
1.1 etheisen 167: c = ch_forw_get();
168: } while (c != '\n' && c != EOI);
169: new_pos = ch_tell();
1.4 millert 170: endline = TRUE;
171: quit_if_one_screen = FALSE;
1.8 nicm 172: } else {
1.5 shadchin 173: new_pos = ch_tell() - backchars;
1.4 millert 174: endline = FALSE;
1.1 etheisen 175: }
176: break;
177: }
178: c = ch_forw_get();
179: }
1.5 shadchin 180:
181: pdone(endline, 1);
182:
1.8 nicm 183: if (is_filtered(base_pos)) {
1.5 shadchin 184: /*
185: * We don't want to display this line.
186: * Get the next line.
187: */
188: curr_pos = new_pos;
189: goto get_forw_line;
190: }
191:
192: if (status_col && is_hilited(base_pos, ch_tell()-1, 1, NULL))
193: set_status_col('*');
1.1 etheisen 194:
1.8 nicm 195: if (squeeze && blankline) {
1.1 etheisen 196: /*
197: * This line is blank.
198: * Skip down to the last contiguous blank line
199: * and pretend it is the one which we are returning.
200: */
201: while ((c = ch_forw_get()) == '\n' || c == '\r')
1.8 nicm 202: if (ABORT_SIGS()) {
1.1 etheisen 203: null_line();
1.8 nicm 204: return (-1);
1.1 etheisen 205: }
206: if (c != EOI)
207: (void) ch_back_get();
208: new_pos = ch_tell();
209: }
210:
211: return (new_pos);
212: }
213:
214: /*
215: * Get the previous line.
216: * A "current" position is passed and a "new" position is returned.
217: * The current position is the position of the first character of
218: * a line. The new position is the position of the first character
219: * of the PREVIOUS line. The line obtained is the one starting at new_pos.
220: */
1.8 nicm 221: off_t
222: back_line(off_t curr_pos)
1.1 etheisen 223: {
1.8 nicm 224: off_t new_pos, begin_new_pos, base_pos;
1.1 etheisen 225: int c;
226: int endline;
1.5 shadchin 227: int backchars;
1.1 etheisen 228:
1.5 shadchin 229: get_back_line:
1.8 nicm 230: if (curr_pos == -1 || curr_pos <= ch_zero()) {
1.1 etheisen 231: null_line();
1.8 nicm 232: return (-1);
1.1 etheisen 233: }
1.5 shadchin 234: if (hilite_search == OPT_ONPLUS || is_filtering() || status_col)
1.8 nicm 235: prep_hilite((curr_pos < 3*size_linebuf) ?
236: 0 : curr_pos - 3*size_linebuf, curr_pos, -1);
237: if (ch_seek(curr_pos-1)) {
1.1 etheisen 238: null_line();
1.8 nicm 239: return (-1);
1.1 etheisen 240: }
241:
1.8 nicm 242: if (squeeze) {
1.1 etheisen 243: /*
244: * Find out if the "current" line was blank.
245: */
1.8 nicm 246: (void) ch_forw_get(); /* Skip the newline */
247: c = ch_forw_get(); /* First char of "current" line */
248: (void) ch_back_get(); /* Restore our position */
1.1 etheisen 249: (void) ch_back_get();
250:
1.8 nicm 251: if (c == '\n' || c == '\r') {
1.1 etheisen 252: /*
253: * The "current" line was blank.
254: * Skip over any preceding blank lines,
255: * since we skipped them in forw_line().
256: */
257: while ((c = ch_back_get()) == '\n' || c == '\r')
1.8 nicm 258: if (ABORT_SIGS()) {
1.1 etheisen 259: null_line();
1.8 nicm 260: return (-1);
1.1 etheisen 261: }
1.8 nicm 262: if (c == EOI) {
1.1 etheisen 263: null_line();
1.8 nicm 264: return (-1);
1.1 etheisen 265: }
266: (void) ch_forw_get();
267: }
268: }
269:
270: /*
271: * Scan backwards until we hit the beginning of the line.
272: */
1.8 nicm 273: for (;;) {
274: if (ABORT_SIGS()) {
1.1 etheisen 275: null_line();
1.8 nicm 276: return (-1);
1.1 etheisen 277: }
278: c = ch_back_get();
1.8 nicm 279: if (c == '\n') {
1.1 etheisen 280: /*
281: * This is the newline ending the previous line.
282: * We have hit the beginning of the line.
283: */
1.5 shadchin 284: base_pos = ch_tell() + 1;
1.1 etheisen 285: break;
286: }
1.8 nicm 287: if (c == EOI) {
1.1 etheisen 288: /*
289: * We have hit the beginning of the file.
290: * This must be the first line in the file.
291: * This must, of course, be the beginning of the line.
292: */
1.5 shadchin 293: base_pos = ch_tell();
1.1 etheisen 294: break;
295: }
296: }
297:
298: /*
299: * Now scan forwards from the beginning of this line.
300: * We keep discarding "printable lines" (based on screen width)
301: * until we reach the curr_pos.
302: *
303: * {{ This algorithm is pretty inefficient if the lines
1.8 nicm 304: * are much longer than the screen width,
1.1 etheisen 305: * but I don't know of any better way. }}
306: */
1.5 shadchin 307: new_pos = base_pos;
1.8 nicm 308: if (ch_seek(new_pos)) {
1.1 etheisen 309: null_line();
1.8 nicm 310: return (-1);
1.1 etheisen 311: }
1.4 millert 312: endline = FALSE;
1.5 shadchin 313: prewind();
314: plinenum(new_pos);
1.8 nicm 315: loop:
1.1 etheisen 316: begin_new_pos = new_pos;
317: (void) ch_seek(new_pos);
318:
1.8 nicm 319: do {
1.1 etheisen 320: c = ch_forw_get();
1.8 nicm 321: if (c == EOI || ABORT_SIGS()) {
1.1 etheisen 322: null_line();
1.8 nicm 323: return (-1);
1.1 etheisen 324: }
325: new_pos++;
1.8 nicm 326: if (c == '\n') {
1.5 shadchin 327: backchars = pflushmbc();
1.8 nicm 328: if (backchars > 0 && !chopline && hshift == 0) {
1.5 shadchin 329: backchars++;
330: goto shift;
331: }
1.4 millert 332: endline = TRUE;
1.1 etheisen 333: break;
334: }
1.5 shadchin 335: backchars = pappend(c, ch_tell()-1);
1.8 nicm 336: if (backchars > 0) {
1.1 etheisen 337: /*
338: * Got a full printable line, but we haven't
339: * reached our curr_pos yet. Discard the line
340: * and start a new one.
341: */
1.8 nicm 342: if (chopline || hshift > 0) {
1.4 millert 343: endline = TRUE;
344: quit_if_one_screen = FALSE;
1.1 etheisen 345: break;
346: }
1.5 shadchin 347: shift:
348: pshift_all();
1.8 nicm 349: while (backchars-- > 0) {
1.5 shadchin 350: (void) ch_back_get();
351: new_pos--;
352: }
1.1 etheisen 353: goto loop;
354: }
355: } while (new_pos < curr_pos);
356:
1.5 shadchin 357: pdone(endline, 0);
358:
1.8 nicm 359: if (is_filtered(base_pos)) {
1.5 shadchin 360: /*
361: * We don't want to display this line.
362: * Get the previous line.
363: */
364: curr_pos = begin_new_pos;
365: goto get_back_line;
366: }
367:
1.8 nicm 368: if (status_col && curr_pos > 0 &&
369: is_hilited(base_pos, curr_pos-1, 1, NULL))
1.5 shadchin 370: set_status_col('*');
1.1 etheisen 371:
372: return (begin_new_pos);
1.4 millert 373: }
374:
375: /*
376: * Set attnpos.
377: */
1.8 nicm 378: void
379: set_attnpos(off_t pos)
1.4 millert 380: {
381: int c;
382:
1.8 nicm 383: if (pos != -1) {
1.4 millert 384: if (ch_seek(pos))
385: return;
1.8 nicm 386: for (;;) {
1.4 millert 387: c = ch_forw_get();
388: if (c == EOI)
389: return;
390: if (c != '\n' && c != '\r')
391: break;
392: pos++;
393: }
394: }
395: start_attnpos = pos;
1.8 nicm 396: for (;;) {
1.4 millert 397: c = ch_forw_get();
398: pos++;
399: if (c == EOI || c == '\n' || c == '\r')
400: break;
401: }
402: end_attnpos = pos;
1.1 etheisen 403: }