160786Sps/* 2240121Sdelphij * Copyright (C) 1984-2012 Mark Nudelman 360786Sps * 460786Sps * You may distribute under the terms of either the GNU General Public 560786Sps * License or the Less License, as specified in the README file. 660786Sps * 7240121Sdelphij * For more information, see the README file. 860786Sps */ 960786Sps 1060786Sps 1160786Sps/* 1260786Sps * High level routines dealing with getting lines of input 1360786Sps * from the file being viewed. 1460786Sps * 1560786Sps * When we speak of "lines" here, we mean PRINTABLE lines; 1660786Sps * lines processed with respect to the screen width. 1760786Sps * We use the term "raw line" to refer to lines simply 1860786Sps * delimited by newlines; not processed with respect to screen width. 1960786Sps */ 2060786Sps 2160786Sps#include "less.h" 2260786Sps 2360786Spsextern int squeeze; 2460786Spsextern int chopline; 2563128Spsextern int hshift; 2660786Spsextern int quit_if_one_screen; 2760786Spsextern int sigs; 2860786Spsextern int ignore_eoi; 29161475Sdelphijextern int status_col; 3060786Spsextern POSITION start_attnpos; 3160786Spsextern POSITION end_attnpos; 3260786Sps#if HILITE_SEARCH 3360786Spsextern int hilite_search; 3460786Spsextern int size_linebuf; 3560786Sps#endif 3660786Sps 3760786Sps/* 3860786Sps * Get the next line. 3960786Sps * A "current" position is passed and a "new" position is returned. 4060786Sps * The current position is the position of the first character of 4160786Sps * a line. The new position is the position of the first character 4260786Sps * of the NEXT line. The line obtained is the line starting at curr_pos. 4360786Sps */ 4460786Sps public POSITION 4560786Spsforw_line(curr_pos) 4660786Sps POSITION curr_pos; 4760786Sps{ 48161475Sdelphij POSITION base_pos; 4960786Sps POSITION new_pos; 5060786Sps register int c; 5160786Sps int blankline; 5260786Sps int endline; 53161475Sdelphij int backchars; 5460786Sps 55191930Sdelphijget_forw_line: 5660786Sps if (curr_pos == NULL_POSITION) 5760786Sps { 5860786Sps null_line(); 5960786Sps return (NULL_POSITION); 6060786Sps } 6160786Sps#if HILITE_SEARCH 62191930Sdelphij if (hilite_search == OPT_ONPLUS || is_filtering() || status_col) 6360786Sps /* 6460786Sps * If we are ignoring EOI (command F), only prepare 6560786Sps * one line ahead, to avoid getting stuck waiting for 6660786Sps * slow data without displaying the data we already have. 6760786Sps * If we're not ignoring EOI, we *could* do the same, but 6860786Sps * for efficiency we prepare several lines ahead at once. 6960786Sps */ 7060786Sps prep_hilite(curr_pos, curr_pos + 3*size_linebuf, 7160786Sps ignore_eoi ? 1 : -1); 7260786Sps#endif 7360786Sps if (ch_seek(curr_pos)) 7460786Sps { 7560786Sps null_line(); 7660786Sps return (NULL_POSITION); 7760786Sps } 7860786Sps 79191930Sdelphij /* 80191930Sdelphij * Step back to the beginning of the line. 81191930Sdelphij */ 82161475Sdelphij base_pos = curr_pos; 83161475Sdelphij for (;;) 84161475Sdelphij { 85161475Sdelphij if (ABORT_SIGS()) 86161475Sdelphij { 87161475Sdelphij null_line(); 88161475Sdelphij return (NULL_POSITION); 89161475Sdelphij } 90161475Sdelphij c = ch_back_get(); 91161475Sdelphij if (c == EOI) 92161475Sdelphij break; 93161475Sdelphij if (c == '\n') 94161475Sdelphij { 95161475Sdelphij (void) ch_forw_get(); 96161475Sdelphij break; 97161475Sdelphij } 98161475Sdelphij --base_pos; 99161475Sdelphij } 10060786Sps 101191930Sdelphij /* 102191930Sdelphij * Read forward again to the position we should start at. 103191930Sdelphij */ 104161475Sdelphij prewind(); 105161475Sdelphij plinenum(base_pos); 106161475Sdelphij (void) ch_seek(base_pos); 107191930Sdelphij new_pos = base_pos; 108191930Sdelphij while (new_pos < curr_pos) 109161475Sdelphij { 110161475Sdelphij if (ABORT_SIGS()) 111161475Sdelphij { 112161475Sdelphij null_line(); 113161475Sdelphij return (NULL_POSITION); 114161475Sdelphij } 115161475Sdelphij c = ch_forw_get(); 116191930Sdelphij backchars = pappend(c, new_pos); 117191930Sdelphij new_pos++; 118161475Sdelphij if (backchars > 0) 119161475Sdelphij { 120161475Sdelphij pshift_all(); 121191930Sdelphij new_pos -= backchars; 122161475Sdelphij while (--backchars >= 0) 123161475Sdelphij (void) ch_back_get(); 124161475Sdelphij } 125161475Sdelphij } 126161475Sdelphij (void) pflushmbc(); 127161475Sdelphij pshift_all(); 128161475Sdelphij 129191930Sdelphij /* 130191930Sdelphij * Read the first character to display. 131191930Sdelphij */ 13260786Sps c = ch_forw_get(); 13360786Sps if (c == EOI) 13460786Sps { 13560786Sps null_line(); 13660786Sps return (NULL_POSITION); 13760786Sps } 13860786Sps blankline = (c == '\n' || c == '\r'); 13960786Sps 140191930Sdelphij /* 141191930Sdelphij * Read each character in the line and append to the line buffer. 142191930Sdelphij */ 14360786Sps for (;;) 14460786Sps { 14560786Sps if (ABORT_SIGS()) 14660786Sps { 14760786Sps null_line(); 14860786Sps return (NULL_POSITION); 14960786Sps } 15060786Sps if (c == '\n' || c == EOI) 15160786Sps { 15260786Sps /* 15360786Sps * End of the line. 15460786Sps */ 155161475Sdelphij backchars = pflushmbc(); 15660786Sps new_pos = ch_tell(); 157161475Sdelphij if (backchars > 0 && !chopline && hshift == 0) 158161475Sdelphij { 159161475Sdelphij new_pos -= backchars + 1; 160161475Sdelphij endline = FALSE; 161161475Sdelphij } else 162161475Sdelphij endline = TRUE; 16360786Sps break; 16460786Sps } 165161475Sdelphij if (c != '\r') 166161475Sdelphij blankline = 0; 16760786Sps 16860786Sps /* 16960786Sps * Append the char to the line and get the next char. 17060786Sps */ 171161475Sdelphij backchars = pappend(c, ch_tell()-1); 172161475Sdelphij if (backchars > 0) 17360786Sps { 17460786Sps /* 17560786Sps * The char won't fit in the line; the line 17660786Sps * is too long to print in the screen width. 17760786Sps * End the line here. 17860786Sps */ 17963128Sps if (chopline || hshift > 0) 18060786Sps { 18160786Sps do 18260786Sps { 183221715Sdelphij if (ABORT_SIGS()) 184221715Sdelphij { 185221715Sdelphij null_line(); 186221715Sdelphij return (NULL_POSITION); 187221715Sdelphij } 18860786Sps c = ch_forw_get(); 18960786Sps } while (c != '\n' && c != EOI); 19060786Sps new_pos = ch_tell(); 19160786Sps endline = TRUE; 19260786Sps quit_if_one_screen = FALSE; 19360786Sps } else 19460786Sps { 195161475Sdelphij new_pos = ch_tell() - backchars; 19660786Sps endline = FALSE; 19760786Sps } 19860786Sps break; 19960786Sps } 20060786Sps c = ch_forw_get(); 20160786Sps } 20260786Sps 203195941Sdelphij pdone(endline, 1); 204191930Sdelphij 205191930Sdelphij#if HILITE_SEARCH 206191930Sdelphij if (is_filtered(base_pos)) 207191930Sdelphij { 208191930Sdelphij /* 209191930Sdelphij * We don't want to display this line. 210191930Sdelphij * Get the next line. 211191930Sdelphij */ 212191930Sdelphij curr_pos = new_pos; 213191930Sdelphij goto get_forw_line; 214191930Sdelphij } 215191930Sdelphij 216191930Sdelphij if (status_col && is_hilited(base_pos, ch_tell()-1, 1, NULL)) 217191930Sdelphij set_status_col('*'); 218191930Sdelphij#endif 219191930Sdelphij 22060786Sps if (squeeze && blankline) 22160786Sps { 22260786Sps /* 22360786Sps * This line is blank. 22460786Sps * Skip down to the last contiguous blank line 22560786Sps * and pretend it is the one which we are returning. 22660786Sps */ 22760786Sps while ((c = ch_forw_get()) == '\n' || c == '\r') 22860786Sps if (ABORT_SIGS()) 22960786Sps { 23060786Sps null_line(); 23160786Sps return (NULL_POSITION); 23260786Sps } 23360786Sps if (c != EOI) 23460786Sps (void) ch_back_get(); 23560786Sps new_pos = ch_tell(); 23660786Sps } 23760786Sps 23860786Sps return (new_pos); 23960786Sps} 24060786Sps 24160786Sps/* 24260786Sps * Get the previous line. 24360786Sps * A "current" position is passed and a "new" position is returned. 24460786Sps * The current position is the position of the first character of 24560786Sps * a line. The new position is the position of the first character 24660786Sps * of the PREVIOUS line. The line obtained is the one starting at new_pos. 24760786Sps */ 24860786Sps public POSITION 24960786Spsback_line(curr_pos) 25060786Sps POSITION curr_pos; 25160786Sps{ 252191930Sdelphij POSITION new_pos, begin_new_pos, base_pos; 25360786Sps int c; 25460786Sps int endline; 255161475Sdelphij int backchars; 25660786Sps 257191930Sdelphijget_back_line: 25860786Sps if (curr_pos == NULL_POSITION || curr_pos <= ch_zero()) 25960786Sps { 26060786Sps null_line(); 26160786Sps return (NULL_POSITION); 26260786Sps } 26360786Sps#if HILITE_SEARCH 264191930Sdelphij if (hilite_search == OPT_ONPLUS || is_filtering() || status_col) 26560786Sps prep_hilite((curr_pos < 3*size_linebuf) ? 26660786Sps 0 : curr_pos - 3*size_linebuf, curr_pos, -1); 26760786Sps#endif 26860786Sps if (ch_seek(curr_pos-1)) 26960786Sps { 27060786Sps null_line(); 27160786Sps return (NULL_POSITION); 27260786Sps } 27360786Sps 27460786Sps if (squeeze) 27560786Sps { 27660786Sps /* 27760786Sps * Find out if the "current" line was blank. 27860786Sps */ 279191930Sdelphij (void) ch_forw_get(); /* Skip the newline */ 280191930Sdelphij c = ch_forw_get(); /* First char of "current" line */ 281191930Sdelphij (void) ch_back_get(); /* Restore our position */ 28260786Sps (void) ch_back_get(); 28360786Sps 28460786Sps if (c == '\n' || c == '\r') 28560786Sps { 28660786Sps /* 28760786Sps * The "current" line was blank. 28860786Sps * Skip over any preceding blank lines, 28960786Sps * since we skipped them in forw_line(). 29060786Sps */ 29160786Sps while ((c = ch_back_get()) == '\n' || c == '\r') 29260786Sps if (ABORT_SIGS()) 29360786Sps { 29460786Sps null_line(); 29560786Sps return (NULL_POSITION); 29660786Sps } 29760786Sps if (c == EOI) 29860786Sps { 29960786Sps null_line(); 30060786Sps return (NULL_POSITION); 30160786Sps } 30260786Sps (void) ch_forw_get(); 30360786Sps } 30460786Sps } 30560786Sps 30660786Sps /* 30760786Sps * Scan backwards until we hit the beginning of the line. 30860786Sps */ 30960786Sps for (;;) 31060786Sps { 31160786Sps if (ABORT_SIGS()) 31260786Sps { 31360786Sps null_line(); 31460786Sps return (NULL_POSITION); 31560786Sps } 31660786Sps c = ch_back_get(); 31760786Sps if (c == '\n') 31860786Sps { 31960786Sps /* 32060786Sps * This is the newline ending the previous line. 32160786Sps * We have hit the beginning of the line. 32260786Sps */ 323191930Sdelphij base_pos = ch_tell() + 1; 32460786Sps break; 32560786Sps } 32660786Sps if (c == EOI) 32760786Sps { 32860786Sps /* 32960786Sps * We have hit the beginning of the file. 33060786Sps * This must be the first line in the file. 33160786Sps * This must, of course, be the beginning of the line. 33260786Sps */ 333191930Sdelphij base_pos = ch_tell(); 33460786Sps break; 33560786Sps } 33660786Sps } 33760786Sps 33860786Sps /* 33960786Sps * Now scan forwards from the beginning of this line. 34060786Sps * We keep discarding "printable lines" (based on screen width) 34160786Sps * until we reach the curr_pos. 34260786Sps * 34360786Sps * {{ This algorithm is pretty inefficient if the lines 34460786Sps * are much longer than the screen width, 34560786Sps * but I don't know of any better way. }} 34660786Sps */ 347191930Sdelphij new_pos = base_pos; 34860786Sps if (ch_seek(new_pos)) 34960786Sps { 35060786Sps null_line(); 35160786Sps return (NULL_POSITION); 35260786Sps } 35360786Sps endline = FALSE; 354161475Sdelphij prewind(); 355161475Sdelphij plinenum(new_pos); 35660786Sps loop: 35760786Sps begin_new_pos = new_pos; 35860786Sps (void) ch_seek(new_pos); 35960786Sps 36060786Sps do 36160786Sps { 36260786Sps c = ch_forw_get(); 36360786Sps if (c == EOI || ABORT_SIGS()) 36460786Sps { 36560786Sps null_line(); 36660786Sps return (NULL_POSITION); 36760786Sps } 36860786Sps new_pos++; 36960786Sps if (c == '\n') 37060786Sps { 371161475Sdelphij backchars = pflushmbc(); 372161475Sdelphij if (backchars > 0 && !chopline && hshift == 0) 373161475Sdelphij { 374161475Sdelphij backchars++; 375161475Sdelphij goto shift; 376161475Sdelphij } 37760786Sps endline = TRUE; 37860786Sps break; 37960786Sps } 380161475Sdelphij backchars = pappend(c, ch_tell()-1); 381161475Sdelphij if (backchars > 0) 38260786Sps { 38360786Sps /* 38460786Sps * Got a full printable line, but we haven't 38560786Sps * reached our curr_pos yet. Discard the line 38660786Sps * and start a new one. 38760786Sps */ 38863128Sps if (chopline || hshift > 0) 38960786Sps { 39060786Sps endline = TRUE; 39160786Sps quit_if_one_screen = FALSE; 39260786Sps break; 39360786Sps } 394161475Sdelphij shift: 395161475Sdelphij pshift_all(); 396161475Sdelphij while (backchars-- > 0) 397161475Sdelphij { 398161475Sdelphij (void) ch_back_get(); 399161475Sdelphij new_pos--; 400161475Sdelphij } 40160786Sps goto loop; 40260786Sps } 40360786Sps } while (new_pos < curr_pos); 40460786Sps 405195941Sdelphij pdone(endline, 0); 40660786Sps 407191930Sdelphij#if HILITE_SEARCH 408191930Sdelphij if (is_filtered(base_pos)) 409191930Sdelphij { 410191930Sdelphij /* 411191930Sdelphij * We don't want to display this line. 412191930Sdelphij * Get the previous line. 413191930Sdelphij */ 414191930Sdelphij curr_pos = begin_new_pos; 415191930Sdelphij goto get_back_line; 416191930Sdelphij } 417191930Sdelphij 418240121Sdelphij if (status_col && curr_pos > 0 && is_hilited(base_pos, curr_pos-1, 1, NULL)) 419191930Sdelphij set_status_col('*'); 420191930Sdelphij#endif 421191930Sdelphij 42260786Sps return (begin_new_pos); 42360786Sps} 42460786Sps 42560786Sps/* 42660786Sps * Set attnpos. 42760786Sps */ 42860786Sps public void 42960786Spsset_attnpos(pos) 43060786Sps POSITION pos; 43160786Sps{ 43260786Sps int c; 43360786Sps 43460786Sps if (pos != NULL_POSITION) 43560786Sps { 43660786Sps if (ch_seek(pos)) 43760786Sps return; 43860786Sps for (;;) 43960786Sps { 44060786Sps c = ch_forw_get(); 44160786Sps if (c == EOI) 44260786Sps return; 44360786Sps if (c != '\n' && c != '\r') 44460786Sps break; 44560786Sps pos++; 44660786Sps } 44760786Sps } 44860786Sps start_attnpos = pos; 44960786Sps for (;;) 45060786Sps { 45160786Sps c = ch_forw_get(); 45260786Sps pos++; 45360786Sps if (c == EOI || c == '\n' || c == '\r') 45460786Sps break; 45560786Sps } 45660786Sps end_attnpos = pos; 45760786Sps} 458