1238730Sdelphij/* 2330571Sdelphij * Copyright (C) 1984-2017 Mark Nudelman 3238730Sdelphij * 4238730Sdelphij * You may distribute under the terms of either the GNU General Public 5238730Sdelphij * License or the Less License, as specified in the README file. 6238730Sdelphij * 7238730Sdelphij * For more information, see the README file. 8238730Sdelphij */ 960786Sps 1060786Sps/* 1160786Sps * High level routines dealing with getting lines of input 1260786Sps * from the file being viewed. 1360786Sps * 1460786Sps * When we speak of "lines" here, we mean PRINTABLE lines; 1560786Sps * lines processed with respect to the screen width. 1660786Sps * We use the term "raw line" to refer to lines simply 1760786Sps * delimited by newlines; not processed with respect to screen width. 1860786Sps */ 1960786Sps 2060786Sps#include "less.h" 2160786Sps 2260786Spsextern int squeeze; 2360786Spsextern int chopline; 2463128Spsextern int hshift; 2560786Spsextern int quit_if_one_screen; 2660786Spsextern int sigs; 2760786Spsextern int ignore_eoi; 28161475Sdelphijextern int status_col; 2960786Spsextern POSITION start_attnpos; 3060786Spsextern POSITION end_attnpos; 3160786Sps#if HILITE_SEARCH 3260786Spsextern int hilite_search; 3360786Spsextern int size_linebuf; 3460786Sps#endif 3560786Sps 3660786Sps/* 3760786Sps * Get the next line. 3860786Sps * A "current" position is passed and a "new" position is returned. 3960786Sps * The current position is the position of the first character of 4060786Sps * a line. The new position is the position of the first character 4160786Sps * of the NEXT line. The line obtained is the line starting at curr_pos. 4260786Sps */ 4360786Sps public POSITION 4460786Spsforw_line(curr_pos) 4560786Sps POSITION curr_pos; 4660786Sps{ 47161475Sdelphij POSITION base_pos; 4860786Sps POSITION new_pos; 49330571Sdelphij int c; 5060786Sps int blankline; 5160786Sps int endline; 52330571Sdelphij int chopped; 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) 63294286Sdelphij { 6460786Sps /* 6560786Sps * If we are ignoring EOI (command F), only prepare 6660786Sps * one line ahead, to avoid getting stuck waiting for 6760786Sps * slow data without displaying the data we already have. 6860786Sps * If we're not ignoring EOI, we *could* do the same, but 6960786Sps * for efficiency we prepare several lines ahead at once. 7060786Sps */ 7160786Sps prep_hilite(curr_pos, curr_pos + 3*size_linebuf, 7260786Sps ignore_eoi ? 1 : -1); 73294286Sdelphij curr_pos = next_unfiltered(curr_pos); 74294286Sdelphij } 7560786Sps#endif 7660786Sps if (ch_seek(curr_pos)) 7760786Sps { 7860786Sps null_line(); 7960786Sps return (NULL_POSITION); 8060786Sps } 8160786Sps 82191930Sdelphij /* 83191930Sdelphij * Step back to the beginning of the line. 84191930Sdelphij */ 85161475Sdelphij base_pos = curr_pos; 86161475Sdelphij for (;;) 87161475Sdelphij { 88161475Sdelphij if (ABORT_SIGS()) 89161475Sdelphij { 90161475Sdelphij null_line(); 91161475Sdelphij return (NULL_POSITION); 92161475Sdelphij } 93161475Sdelphij c = ch_back_get(); 94161475Sdelphij if (c == EOI) 95161475Sdelphij break; 96161475Sdelphij if (c == '\n') 97161475Sdelphij { 98161475Sdelphij (void) ch_forw_get(); 99161475Sdelphij break; 100161475Sdelphij } 101161475Sdelphij --base_pos; 102161475Sdelphij } 10360786Sps 104191930Sdelphij /* 105191930Sdelphij * Read forward again to the position we should start at. 106191930Sdelphij */ 107161475Sdelphij prewind(); 108161475Sdelphij plinenum(base_pos); 109161475Sdelphij (void) ch_seek(base_pos); 110191930Sdelphij new_pos = base_pos; 111191930Sdelphij while (new_pos < curr_pos) 112161475Sdelphij { 113161475Sdelphij if (ABORT_SIGS()) 114161475Sdelphij { 115161475Sdelphij null_line(); 116161475Sdelphij return (NULL_POSITION); 117161475Sdelphij } 118161475Sdelphij c = ch_forw_get(); 119191930Sdelphij backchars = pappend(c, new_pos); 120191930Sdelphij new_pos++; 121161475Sdelphij if (backchars > 0) 122161475Sdelphij { 123161475Sdelphij pshift_all(); 124191930Sdelphij new_pos -= backchars; 125161475Sdelphij while (--backchars >= 0) 126161475Sdelphij (void) ch_back_get(); 127161475Sdelphij } 128161475Sdelphij } 129161475Sdelphij (void) pflushmbc(); 130161475Sdelphij pshift_all(); 131161475Sdelphij 132191930Sdelphij /* 133191930Sdelphij * Read the first character to display. 134191930Sdelphij */ 13560786Sps c = ch_forw_get(); 13660786Sps if (c == EOI) 13760786Sps { 13860786Sps null_line(); 13960786Sps return (NULL_POSITION); 14060786Sps } 14160786Sps blankline = (c == '\n' || c == '\r'); 14260786Sps 143191930Sdelphij /* 144191930Sdelphij * Read each character in the line and append to the line buffer. 145191930Sdelphij */ 146330571Sdelphij chopped = FALSE; 14760786Sps for (;;) 14860786Sps { 14960786Sps if (ABORT_SIGS()) 15060786Sps { 15160786Sps null_line(); 15260786Sps return (NULL_POSITION); 15360786Sps } 15460786Sps if (c == '\n' || c == EOI) 15560786Sps { 15660786Sps /* 15760786Sps * End of the line. 15860786Sps */ 159161475Sdelphij backchars = pflushmbc(); 16060786Sps new_pos = ch_tell(); 161161475Sdelphij if (backchars > 0 && !chopline && hshift == 0) 162161475Sdelphij { 163161475Sdelphij new_pos -= backchars + 1; 164161475Sdelphij endline = FALSE; 165161475Sdelphij } else 166161475Sdelphij endline = TRUE; 16760786Sps break; 16860786Sps } 169161475Sdelphij if (c != '\r') 170161475Sdelphij blankline = 0; 17160786Sps 17260786Sps /* 17360786Sps * Append the char to the line and get the next char. 17460786Sps */ 175161475Sdelphij backchars = pappend(c, ch_tell()-1); 176161475Sdelphij if (backchars > 0) 17760786Sps { 17860786Sps /* 17960786Sps * The char won't fit in the line; the line 18060786Sps * is too long to print in the screen width. 18160786Sps * End the line here. 18260786Sps */ 18363128Sps if (chopline || hshift > 0) 18460786Sps { 18560786Sps do 18660786Sps { 187221715Sdelphij if (ABORT_SIGS()) 188221715Sdelphij { 189221715Sdelphij null_line(); 190221715Sdelphij return (NULL_POSITION); 191221715Sdelphij } 19260786Sps c = ch_forw_get(); 19360786Sps } while (c != '\n' && c != EOI); 19460786Sps new_pos = ch_tell(); 19560786Sps endline = TRUE; 19660786Sps quit_if_one_screen = FALSE; 197330571Sdelphij chopped = TRUE; 19860786Sps } else 19960786Sps { 200161475Sdelphij new_pos = ch_tell() - backchars; 20160786Sps endline = FALSE; 20260786Sps } 20360786Sps break; 20460786Sps } 20560786Sps c = ch_forw_get(); 20660786Sps } 20760786Sps 208330571Sdelphij pdone(endline, chopped, 1); 209191930Sdelphij 210191930Sdelphij#if HILITE_SEARCH 211191930Sdelphij if (is_filtered(base_pos)) 212191930Sdelphij { 213191930Sdelphij /* 214191930Sdelphij * We don't want to display this line. 215191930Sdelphij * Get the next line. 216191930Sdelphij */ 217191930Sdelphij curr_pos = new_pos; 218191930Sdelphij goto get_forw_line; 219191930Sdelphij } 220191930Sdelphij 221191930Sdelphij if (status_col && is_hilited(base_pos, ch_tell()-1, 1, NULL)) 222191930Sdelphij set_status_col('*'); 223191930Sdelphij#endif 224191930Sdelphij 22560786Sps if (squeeze && blankline) 22660786Sps { 22760786Sps /* 22860786Sps * This line is blank. 22960786Sps * Skip down to the last contiguous blank line 23060786Sps * and pretend it is the one which we are returning. 23160786Sps */ 23260786Sps while ((c = ch_forw_get()) == '\n' || c == '\r') 23360786Sps if (ABORT_SIGS()) 23460786Sps { 23560786Sps null_line(); 23660786Sps return (NULL_POSITION); 23760786Sps } 23860786Sps if (c != EOI) 23960786Sps (void) ch_back_get(); 24060786Sps new_pos = ch_tell(); 24160786Sps } 24260786Sps 24360786Sps return (new_pos); 24460786Sps} 24560786Sps 24660786Sps/* 24760786Sps * Get the previous line. 24860786Sps * A "current" position is passed and a "new" position is returned. 24960786Sps * The current position is the position of the first character of 25060786Sps * a line. The new position is the position of the first character 25160786Sps * of the PREVIOUS line. The line obtained is the one starting at new_pos. 25260786Sps */ 25360786Sps public POSITION 25460786Spsback_line(curr_pos) 25560786Sps POSITION curr_pos; 25660786Sps{ 257191930Sdelphij POSITION new_pos, begin_new_pos, base_pos; 25860786Sps int c; 25960786Sps int endline; 260330571Sdelphij int chopped; 261161475Sdelphij int backchars; 26260786Sps 263191930Sdelphijget_back_line: 26460786Sps if (curr_pos == NULL_POSITION || curr_pos <= ch_zero()) 26560786Sps { 26660786Sps null_line(); 26760786Sps return (NULL_POSITION); 26860786Sps } 26960786Sps#if HILITE_SEARCH 270191930Sdelphij if (hilite_search == OPT_ONPLUS || is_filtering() || status_col) 27160786Sps prep_hilite((curr_pos < 3*size_linebuf) ? 27260786Sps 0 : curr_pos - 3*size_linebuf, curr_pos, -1); 27360786Sps#endif 27460786Sps if (ch_seek(curr_pos-1)) 27560786Sps { 27660786Sps null_line(); 27760786Sps return (NULL_POSITION); 27860786Sps } 27960786Sps 28060786Sps if (squeeze) 28160786Sps { 28260786Sps /* 28360786Sps * Find out if the "current" line was blank. 28460786Sps */ 285191930Sdelphij (void) ch_forw_get(); /* Skip the newline */ 286191930Sdelphij c = ch_forw_get(); /* First char of "current" line */ 287191930Sdelphij (void) ch_back_get(); /* Restore our position */ 28860786Sps (void) ch_back_get(); 28960786Sps 29060786Sps if (c == '\n' || c == '\r') 29160786Sps { 29260786Sps /* 29360786Sps * The "current" line was blank. 29460786Sps * Skip over any preceding blank lines, 29560786Sps * since we skipped them in forw_line(). 29660786Sps */ 29760786Sps while ((c = ch_back_get()) == '\n' || c == '\r') 29860786Sps if (ABORT_SIGS()) 29960786Sps { 30060786Sps null_line(); 30160786Sps return (NULL_POSITION); 30260786Sps } 30360786Sps if (c == EOI) 30460786Sps { 30560786Sps null_line(); 30660786Sps return (NULL_POSITION); 30760786Sps } 30860786Sps (void) ch_forw_get(); 30960786Sps } 31060786Sps } 31160786Sps 31260786Sps /* 31360786Sps * Scan backwards until we hit the beginning of the line. 31460786Sps */ 31560786Sps for (;;) 31660786Sps { 31760786Sps if (ABORT_SIGS()) 31860786Sps { 31960786Sps null_line(); 32060786Sps return (NULL_POSITION); 32160786Sps } 32260786Sps c = ch_back_get(); 32360786Sps if (c == '\n') 32460786Sps { 32560786Sps /* 32660786Sps * This is the newline ending the previous line. 32760786Sps * We have hit the beginning of the line. 32860786Sps */ 329191930Sdelphij base_pos = ch_tell() + 1; 33060786Sps break; 33160786Sps } 33260786Sps if (c == EOI) 33360786Sps { 33460786Sps /* 33560786Sps * We have hit the beginning of the file. 33660786Sps * This must be the first line in the file. 33760786Sps * This must, of course, be the beginning of the line. 33860786Sps */ 339191930Sdelphij base_pos = ch_tell(); 34060786Sps break; 34160786Sps } 34260786Sps } 34360786Sps 34460786Sps /* 34560786Sps * Now scan forwards from the beginning of this line. 34660786Sps * We keep discarding "printable lines" (based on screen width) 34760786Sps * until we reach the curr_pos. 34860786Sps * 34960786Sps * {{ This algorithm is pretty inefficient if the lines 35060786Sps * are much longer than the screen width, 35160786Sps * but I don't know of any better way. }} 35260786Sps */ 353191930Sdelphij new_pos = base_pos; 35460786Sps if (ch_seek(new_pos)) 35560786Sps { 35660786Sps null_line(); 35760786Sps return (NULL_POSITION); 35860786Sps } 35960786Sps endline = FALSE; 360161475Sdelphij prewind(); 361161475Sdelphij plinenum(new_pos); 36260786Sps loop: 36360786Sps begin_new_pos = new_pos; 36460786Sps (void) ch_seek(new_pos); 365330571Sdelphij chopped = FALSE; 36660786Sps 36760786Sps do 36860786Sps { 36960786Sps c = ch_forw_get(); 37060786Sps if (c == EOI || ABORT_SIGS()) 37160786Sps { 37260786Sps null_line(); 37360786Sps return (NULL_POSITION); 37460786Sps } 37560786Sps new_pos++; 37660786Sps if (c == '\n') 37760786Sps { 378161475Sdelphij backchars = pflushmbc(); 379161475Sdelphij if (backchars > 0 && !chopline && hshift == 0) 380161475Sdelphij { 381161475Sdelphij backchars++; 382161475Sdelphij goto shift; 383161475Sdelphij } 38460786Sps endline = TRUE; 38560786Sps break; 38660786Sps } 387161475Sdelphij backchars = pappend(c, ch_tell()-1); 388161475Sdelphij if (backchars > 0) 38960786Sps { 39060786Sps /* 39160786Sps * Got a full printable line, but we haven't 39260786Sps * reached our curr_pos yet. Discard the line 39360786Sps * and start a new one. 39460786Sps */ 39563128Sps if (chopline || hshift > 0) 39660786Sps { 39760786Sps endline = TRUE; 398330571Sdelphij chopped = TRUE; 39960786Sps quit_if_one_screen = FALSE; 40060786Sps break; 40160786Sps } 402161475Sdelphij shift: 403161475Sdelphij pshift_all(); 404161475Sdelphij while (backchars-- > 0) 405161475Sdelphij { 406161475Sdelphij (void) ch_back_get(); 407161475Sdelphij new_pos--; 408161475Sdelphij } 40960786Sps goto loop; 41060786Sps } 41160786Sps } while (new_pos < curr_pos); 41260786Sps 413330571Sdelphij pdone(endline, chopped, 0); 41460786Sps 415191930Sdelphij#if HILITE_SEARCH 416191930Sdelphij if (is_filtered(base_pos)) 417191930Sdelphij { 418191930Sdelphij /* 419191930Sdelphij * We don't want to display this line. 420191930Sdelphij * Get the previous line. 421191930Sdelphij */ 422191930Sdelphij curr_pos = begin_new_pos; 423191930Sdelphij goto get_back_line; 424191930Sdelphij } 425191930Sdelphij 426237613Sdelphij if (status_col && curr_pos > 0 && is_hilited(base_pos, curr_pos-1, 1, NULL)) 427191930Sdelphij set_status_col('*'); 428191930Sdelphij#endif 429191930Sdelphij 43060786Sps return (begin_new_pos); 43160786Sps} 43260786Sps 43360786Sps/* 43460786Sps * Set attnpos. 43560786Sps */ 43660786Sps public void 43760786Spsset_attnpos(pos) 43860786Sps POSITION pos; 43960786Sps{ 44060786Sps int c; 44160786Sps 44260786Sps if (pos != NULL_POSITION) 44360786Sps { 44460786Sps if (ch_seek(pos)) 44560786Sps return; 44660786Sps for (;;) 44760786Sps { 44860786Sps c = ch_forw_get(); 44960786Sps if (c == EOI) 45060786Sps break; 451294286Sdelphij if (c == '\n' || c == '\r') 452294286Sdelphij { 453294286Sdelphij (void) ch_back_get(); 454294286Sdelphij break; 455294286Sdelphij } 45660786Sps pos++; 45760786Sps } 458294286Sdelphij end_attnpos = pos; 459294286Sdelphij for (;;) 460294286Sdelphij { 461294286Sdelphij c = ch_back_get(); 462294286Sdelphij if (c == EOI || c == '\n' || c == '\r') 463294286Sdelphij break; 464294286Sdelphij pos--; 465294286Sdelphij } 46660786Sps } 46760786Sps start_attnpos = pos; 46860786Sps} 469