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